Back to Blog
critical SEVERITY4 min read

chrome.runtime.onMessage: Missing Sender Validation in Extension

A critical authentication flaw in a Chrome extension's message handling allowed arbitrary extensions and malicious web pages to trigger sensitive operations including script injection and tab manipulation. The vulnerability existed because chrome.runtime.onMessage listeners processed requests without verifying sender identity or origin, trusting any message source by default.

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published September 25, 2026•Reviewed September 25, 2026

Answer Summary

The affected code is a Chrome extension's background script handling chrome.runtime.onMessage events without sender validation. An attacker with a malicious extension or compromised web page could inject scripts into TikTok tabs, create arbitrary tabs, and manipulate the extension's internal job state. The fix adds explicit validation: messages are rejected unless sender.id matches chrome.runtime.id, and for tab-originating messages, the URL must match https://tiktok.com. CWE-287 (Improper Authentication).

Vulnerability at a Glance

cweCWE-287
fixAdded sender.id and origin URL validation before processing any message action
riskMalicious extensions or compromised origins trigger privileged operations
languageJavaScript
root causechrome.runtime.onMessage listener accepted all messages without sender validation
vulnerabilityMissing authentication on inter-extension messaging

Affected Versions

Affected not applicable (first-party code)
Fixed in not applicable (first-party code) — see PR for fix commit
Ecosystem Chrome Extension (Manifest V3)
CVE / GHSA not assigned
CWE CWE-287: Improper Authentication

The Vulnerability Explained

Chrome extensions rely on chrome.runtime.onMessage for internal communication between background scripts, content scripts, and popup pages. By design, this API accepts messages from multiple sources: other extension contexts, content scripts injected into web pages, and even other extensions if permissions allow. The critical mistake here was assuming message receipt implies trust.

The vulnerable code processed sensitive actions immediately upon message receipt:

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === "runFinished") {
    clearStoredActiveJob(sender.tab && sender.tab.id, () => sendResponse({ ok: true }));
    return true;
  }
  // ... handlers for startRemovingFavorites, injectPageRemoveListener, etc.
});

The sender parameter contains identity metadata that was completely ignored. An attacker could exploit this through two vectors:

Cross-extension attack: Any installed extension with externally_connectable permissions or the ability to message other extensions could send forged startRemovingFavorites or injectPageRemoveListener commands. The handler would execute chrome.scripting.executeScript or chrome.tabs.create under the victim extension's elevated permissions.

Compromised origin attack: The extension injects content scripts into TikTok pages. If a TikTok tab were compromised through XSS or if a malicious site framed TikTok content, that JavaScript could message the background script directly. The sender.tab property would be populated, making the message appear legitimate without actual extension authorization.

The real impact extends beyond irritation: chrome.scripting.executeScript allows arbitrary code execution in any tab the extension can access. An attacker could pivot from messaging to full tab compromise, steal TikTok session data, or manipulate the extension's proprietary API orchestration logic.

The Fix

The patch adds authentication at the message entry point, before any action handler executes:

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (!sender || sender.id !== chrome.runtime.id) return false;
  if (sender.tab && !/^https:\/\/(www\.)?tiktok\.com\//.test(sender.url || "")) return false;

  if (request.action === "runFinished") {
    clearStoredActiveJob(sender.tab && sender.tab.id, () => sendResponse({ ok: true }));
    return true;
  }
  // ... remaining handlers
});

The first line implements identity validation: sender.id must match chrome.runtime.id, which is cryptographically bound to the extension's signing key. This blocks all cross-extension messages and any web-originated messages that lack proper extension context.

The second line adds origin validation for content script messages: when sender.tab exists, the URL must match the TikTok domain pattern. This prevents a compromised content script on an attacker-controlled site from messaging the extension—even if somehow injected with the extension's ID.

Returning false immediately for failed validation is idiomatic: it tells Chrome's message port that no asynchronous response will follow, allowing cleanup.

Key Takeaways

  • chrome.runtime.onMessage is unauthenticated by default — every handler must explicitly validate sender.id against chrome.runtime.id before trusting any message content.

  • Content script origin requires separate verification — sender.id alone is insufficient when messages may originate from injected scripts; the sender.url must match expected patterns.

  • Sensitive APIs compound messaging risks — chrome.scripting.executeScript, chrome.tabs.create, and cross-origin API calls should never be reachable without cryptographic identity proof.

  • Early validation prevents handler sprawl — placing checks at the listener entry point, rather than in each action handler, eliminates the risk of inconsistent validation across message types.

How Orbis AppSec Detected This

Source: The request parameter from chrome.runtime.onMessage events, containing arbitrary action commands from any caller.

Sink: chrome.scripting.executeScript, chrome.tabs.create, and TikTok API orchestration calls triggered by message handlers including startRemovingFavorites and injectPageRemoveListener.

Missing control: No validation of sender.id against chrome.runtime.id, and no verification that sender.tab.url matches expected origins before executing privileged operations.

CWE: CWE-287 — Improper Authentication. The extension failed to authenticate message sources before acting on their contents.

Fix: Added explicit sender identity verification requiring sender.id === chrome.runtime.id and origin URL pattern matching for tab-originating messages.

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

This vulnerability illustrates a systemic pattern in browser extension security: the convenience of chrome.runtime.onMessage creates an implicit trust boundary that developers often fail to harden. The fix demonstrates proper defense-in-depth—cryptographic identity verification plus origin whitelisting—applied at the earliest possible point. For extension developers, the lesson is mechanical: every onMessage listener must begin with sender validation, or it becomes a privileged API exposed to the entire extension ecosystem and any compromised web origin.

Prevention and further reading

Frequently Asked Questions

Why does the fix check sender.tab separately from sender.id?

The extension handles messages from both internal extension contexts (no tab) and content scripts injected into TikTok pages (has tab). The sender.id check verifies extension origin; the tab URL check verifies web origin when applicable.

Could a malicious TikTok page exploit this before the fix?

Yes. Any JavaScript executing on tiktok.com could send messages to the extension's background script. The fix restricts this to the extension's own content scripts by requiring sender.id to match chrome.runtime.id.

What happens to messages that fail the new validation?

The handler returns false immediately, which signals to Chrome that the message will not be processed and no response will be sent. This silently drops unauthorized requests.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #8

Related Articles

high

undici 8.10.0 Cache Poisoning: CVE-2026-85152 Auth Bypass

undici, the HTTP client used by Node.js's `fetch()` implementation, shipped a caching layer that did not properly isolate cached responses by origin, letting a response poisoned on one origin be served to requests for another. This created a path to cross-origin authentication bypass, tracked as CVE-2026-85152 and fixed in undici 8.10.2.

critical

Hybridauth Telegram OAuth Timing Attack in `authenticateCheckError()`

The Telegram OAuth provider in Hybridauth relied on `strcmp()` to validate HMAC-SHA256 signatures, exposing a timing side-channel that could allow attackers to forge authentication tokens character by character. The fix replaces this with PHP's timing-safe `hash_equals()` function, eliminating the information leak.

critical

Node.js Auth Query SQL Injection via Group Code Interpolation

A sign-in authorization check built its SQL query by mapping an `authorizedGroups` array into quoted string literals and joining them directly into a template literal, creating a classic SQL injection point in a critical authentication path. The fix replaces every interpolated value — including the previously "typed" parameter — with `?` placeholders bound through a value-builder helper, closing off the injection vector entirely.

high

PHP session_start() Missing Secure Cookie Flags in lasturl.php

The `session_start()` call in the last URL tracking component failed to set secure session cookie parameters, allowing session hijacking via man-in-the-middle attacks on HTTP connections or XSS exploitation. The fix configures `session_set_cookie_params()` with `httponly`, `secure`, and `samesite` attributes before starting the session.

critical

Tung Tung Tracker Admin API: Missing Authentication in `/api/sync`

The Tung Tung Tracker administrative API endpoints (`/api/sync`, `/api/backfill`, `/api/show`, `/api/overlay/hide`) relied solely on localhost origin and a static `X-Tracker` header for protection, allowing any local process to execute privileged operations. The fix introduces proper session-based authentication and a random IPC secret for desktop-to-server communication.

critical

POST /api/generate Lacks Authentication, Allowing Unauthenticated

A resume generation endpoint in a Node.js backend accepted requests from any caller with network access, allowing attackers to consume OpenAI API quota without restriction. The vulnerability stemmed from missing authentication middleware on a cost-bearing endpoint. The fix adds mandatory API key validation via HTTP headers before processing any generation requests.