Postmortem: We Shipped postMessage('*') Because It Worked and We Didn't Think About Who Else Would Receive It
TLDR
During a security review of our VS Code webview editor, an audit flagged fivepostMessage invocations utilizing '' target origins. The wildcard argument had been copied from early tutorial examples and worked without issue during development. However, passing '' allowed any embedding frame to inspect outgoing messages. We replaced all wildcard targets with window.location.origin and routed all messaging through a centralized CwsBridge module.
| Audit Milestone | Pre-Audit Wildcard Implementation | Post-Audit Bridge Architecture |
|---|---|---|
| Outbound Target Origin | '*' (Delivers to any domain) | window.location.origin |
| Inbound Event Handler | Unfiltered addEventListener | Strict origin verification guard |
| Code Structure | Ad-hoc postMessage calls across 5 files | Centralized CwsBridge utility module |
Problem statement: the origin of copy-pasted wildcards
Our editor runs inside a VS Code webview iframe.
During initial development, we implemented cross-frame communication using standard postMessage snippets copied from online documentation:
// DEPRECATED: Initial tutorial-copied postMessage calls
window.parent.postMessage({ type: 'cws:ready' }, '*');
window.parent.postMessage({ type: 'tool:state', payload: canvasState }, '*');
Because the code worked smoothly inside VS Code, the wildcard origins remained unnoticed until a formal security audit.
Technical failure mode: auditing open broadcast channels
The security audit identified two major concerns:
- Unbounded Receiver Audience: Passing
'*'meant any webpage embedding the tool could receive state broadcasts. - Future Escalation Risk: As developers added user state or document payload attributes to
canvasState, the open channel would expose sensitive data without warning.
The fix & architecture: centralized bridge module
We removed all ad-hoc postMessage calls across the codebase and created a single CwsBridge utility module to manage cross-frame transport:
// REFACTORED: Centralized Secure Messaging Bridge (CwsBridge.js)
export const CwsBridge = {
targetOrigin: window.location.origin,
send(type, payload) { try { window.parent.postMessage({ type, payload }, this.targetOrigin); } catch (err) { console.error('Bridge postMessage failed:', err); } },
onData(handler) { window.addEventListener('message', (e) => { // Validate origin against expected same-origin or VS Code webview scheme if (e.origin !== this.targetOrigin && !e.origin.startsWith('vscode-webview://')) { return; } handler(e.data); }); } };
All feature components now communicate via CwsBridge.send('tool:state', payload), guaranteeing target origin enforcement across the entire application.
Rule of thumb: Encapsulate all cross-frame messaging inside a single bridge module that enforces target origin boundaries automatically.