T05 · Unauthorized Access and Privilege Escalation
Warning
- Location
- qq-music-ctl.js:251
- Finding
- Disclosure of Unrelated Browser Tab Metadata<![CDATA[ ## Vulnerability Details **File Location**: `qq-music-ctl.js`, lines 251–262 **Vulnerability Type**: Browser-wide metadata disclosure beyond the declared domain boundary **Risk Level**: Medium ### Vulnerable Code ```js async function actionTabs() { const entry = await discoverEndpoint(); output({ browser: entry.version.Browser || entry.version['Browser'] || '', baseUrl: entry.baseUrl, tabs: pageTargets(entry).map(t => ({ id: t.id, title: t.title, url: t.url, isPlayer: isPlayerTarget(t), isQQMusic: isQQMusicTarget(t), })), }); } ``` ### Technical Analysis The `tabs` action obtains all page targets exposed by the connected browser's Chrome DevTools Protocol endpoint and prints each target's ID, title, and complete URL. It does not filter the returned targets through `isQQMusicTarget` before exposing their metadata. The domain restrictions elsewhere in the implementation prevent DOM evaluation on non-QQ-Music pages, but they do not protect metadata processed by this action. Consequently, this behavior conflicts with the documented security boundary that the Skill only operates on `y.qq.com` tabs. Browser titles and URLs can contain sensitive information, including: - Search terms - Account or user identifiers - Private document identifiers - Internal hostnames and application routes - Session-like or authorization parameters embedded in URLs Enumerating CDP targets may be necessary to locate a QQ Music tab, but returning metadata for every unrelated page is not necessary for the Skill's declared music-control functionality. ### Attack Path 1. A user starts a CDP-enabled browser that contains both QQ Music and unrelated tabs. 2. The browser profile may contain private services, documents, searches, or internal applications. 3. An Agent or local caller invokes: ```bash node qq-music-ctl.js tabs ``` 4. The script requests `/json/list` from the local CDP endpoint. 5. `pageTargets(entry ...[truncated 1018 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Filter page targets before constructing the response: ```js async function actionTabs() { const entry = await discoverEndpoint(); const pages = pageTargets(entry); const qqMusicTabs = pages.filter(isQQMusicTarget); output({ browser: entry.version.Browser || entry.version['Browser'] || '', baseUrl: entry.baseUrl, tabs: qqMusicTabs.map(t => ({ id: t.id, title: t.title, url: t.url, isPlayer: isPlayerTarget(t), isQQMusic: true, })), unrelatedTabCount: pages.length - qqMusicTabs.length, }); } ``` Additional hardening measures: 1. Do not return IDs, titles, or URLs for rejected targets. 2. If diagnostic information is required, return only an aggregate count of unrelated tabs. 3. Rename or document the action so that its actual disclosure scope cannot be misunderstood. 4. Continue requiring or strongly encouraging a dedicated browser profile containing only QQ Music. 5. Consider disabling the `tabs` action by default and requiring an explicit diagnostic option to expose even QQ Music target metadata. ]]>
