T09 · Insecure Skill Coding Practices
Note
- Location
- skill.md:155
- Finding
- Unrestricted Cross-Window Theme Synchronization Messages## Vulnerability Details **File Location**: `skill.md`, lines 155-162 and 316-328 **Vulnerability Type**: Unvalidated cross-window messaging **Risk Level**: Low ### Vulnerable Code ```javascript window.addEventListener('message', function (e) { if (e.data && e.data.type === 'pusa-theme') { const theme = e.data.theme; document.documentElement.setAttribute('data-theme', theme); localStorage.setItem('pusa-theme', theme); const btn = document.getElementById('themeToggle'); if (btn) btn.textContent = theme === 'dark' ? '☀️ 明亮' : '🌙 暗黑'; } }); ``` ```javascript const iframe = document.querySelector('#iframeContainer iframe'); if (iframe && iframe.contentWindow) { try { iframe.contentWindow.postMessage({ type: 'pusa-theme', theme: next }, '*'); } catch(e) {} } ``` ```javascript iframe.onload = () => { const theme = document.documentElement.getAttribute('data-theme'); try { iframe.contentWindow.postMessage({ type: 'pusa-theme', theme }, '*'); } catch(e) {} }; ``` ### Technical Analysis The prescribed message listener trusts any message whose payload contains a matching `type`. It does not validate `e.origin` or `e.source`, and it does not restrict `e.data.theme` to the expected `dark` and `light` values. An untrusted window with a reference to the generated report can therefore supply an arbitrary string that is persisted in `localStorage` and assigned to the root element's `data-theme` attribute. The sending examples also use the wildcard target origin `'*'`. If the iframe is navigated to an unexpected origin before a message is sent, that recipient can receive the theme synchronization payload. This does not directly establish script execution because the value is assigned through `setAttribute` and `textContent`, rather than inserted as executable HTML. The confirmed exposure is unauthorized cross-window state manipulation and overly broad message delivery. ### Att ...[truncated 1396 chars]
- Remediation
- ## Remediation Suggestions 1. Permit messages only from the exact trusted application origin: ```javascript const TRUSTED_ORIGIN = 'https://reports.example.com'; window.addEventListener('message', function (e) { if (e.origin !== TRUSTED_ORIGIN) return; if (e.source !== window.parent) return; if (!e.data || e.data.type !== 'pusa-theme') return; if (!['dark', 'light'].includes(e.data.theme)) return; const theme = e.data.theme; document.documentElement.setAttribute('data-theme', theme); localStorage.setItem('pusa-theme', theme); const btn = document.getElementById('themeToggle'); if (btn) { btn.textContent = theme === 'dark' ? '☀️ Light' : '🌙 Dark'; } }); ``` 2. Replace wildcard target origins with the recipient's exact origin: ```javascript iframe.contentWindow.postMessage( { type: 'pusa-theme', theme: next }, TRUSTED_ORIGIN ); ``` 3. Validate locally restored values before applying them: ```javascript const stored = localStorage.getItem('pusa-theme'); const theme = stored === 'light' || stored === 'dark' ? stored : 'dark'; ``` 4. Verify that the iframe URL belongs to the expected origin before sending a message. Where feasible, also compare the incoming event's `source` with the known parent or iframe window. 5. If cross-origin synchronization is unnecessary, remove `postMessage` synchronization entirely and keep theme selection local to each document.
