Security Upgrades in the Chromium chrome.scripting API
This article explores how the modern chrome.scripting
API in Chromium-based browsers significantly enhances security compared
to the legacy tabs.executeScript method. Introduced as a
core component of the Manifest V3 architecture, this updated API
mitigates remote code execution risks, enforces strict code separation,
prevents injection vulnerabilities through safer argument passing, and
adheres to the principle of least privilege. By examining these
foundational changes, this overview explains how modern browser
extensions better protect user data and system integrity.
Elimination of Arbitrary String Execution
The most critical security improvement in the
chrome.scripting API is the complete removal of arbitrary
string execution. The legacy tabs.executeScript method
included a code property, which accepted a raw string of
JavaScript to be executed directly in the context of a web page. This
functioned similarly to JavaScript's dangerous eval()
method, allowing extensions to fetch unverified payloads from external
servers and run them dynamically.
The chrome.scripting.executeScript method removes the
code property entirely. Extensions are now restricted to
executing static JavaScript files bundled directly within the extension
package, or specific JavaScript functions already defined within the
extension's source code. This architectural shift effectively
neutralizes the threat of Remote Code Execution (RCE) via compromised
extension servers.
Safer Parameter Passing
In the legacy system, passing variables from an extension's
background script into a target tab required concatenating strings
directly into the code property. If those variables
contained unsanitized user input or data scraped from an untrusted
webpage, it created severe Cross-Site Scripting (XSS) and code injection
vulnerabilities.
The chrome.scripting API resolves this flaw by
introducing the func and args properties.
Instead of building a string of code, developers pass a reference to a
pre-written JavaScript function via func and provide an
array of variables via args. Chromium safely serializes and
deserializes these arguments using JSON before passing them to the
function in the target tab. This completely separates data from
executable code, making traditional injection attacks impossible during
script execution.
Enhanced Web Store Reviewability
By banning the execution of arbitrary strings and remotely hosted
code, the chrome.scripting API ensures that all executable
logic is self-contained within the extension's installation package.
This change directly improves the effectiveness of automated and manual
security reviews conducted by browser web stores.
Under the legacy tabs.executeScript method, a malicious
actor could submit a benign extension that passed initial store reviews,
only to later fetch and execute malicious strings of code from a
third-party server. With the modern API, reviewers can statically
analyze the entirety of an extension's capabilities before it ever
reaches the user, knowing the extension cannot dynamically alter its
core behavior post-installation.
Principle of Least Privilege
Previously, script injection was coupled with the
chrome.tabs API, blurring the lines between simple tab
management and the invasive modification of web page content. The modern
approach separates these concerns by moving execution logic into its own
namespace and requiring the explicit "scripting" permission
in the extension's manifest file.
This enforces the security principle of least privilege. Users and
security auditors can now immediately identify if an extension intends
to run code on web pages simply by looking at the required API
permissions, rather than guessing how the tabs API is being
utilized behind the scenes.
Explicit Execution World Management
The chrome.scripting API provides strict, standardized
control over the execution environment via the world
property. By default, injected scripts run in an ISOLATED
world. This environment allows the injected script to access and
manipulate the webpage's Document Object Model (DOM), but completely
walls it off from the host page's JavaScript variables, functions, and
prototypes. This isolation prevents malicious websites from hijacking
extension logic or reading sensitive extension variables.
While the legacy API also utilized isolated worlds, developers who
needed to interact with the host page's JavaScript had to manually
inject <script> tags into the DOM—a messy workaround
that often led to security loopholes and race conditions. The
chrome.scripting API allows developers to explicitly
declare the MAIN world in the API call if page-level
interaction is strictly necessary. This makes risky interactions
intentional, standardized, and easily auditable by security tools.