Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ setTimeout("alert('Hello World!');", 500);
const f = new Function("console.log('foo');");
```

If an extension needs to run code that relies on `eval()`-like constructs, such as some templating libraries, it can isolate that code in a [sandboxed page](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/sandbox) instead of loosening the extension's CSP.

### Inline JavaScript

Under the default CSP, inline JavaScript is not executed. This disallows both JavaScript placed directly in `<script>` tags and inline event handlers, meaning that the following are not permitted:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ In Manifest V3, the `content_security_policy` key is an object that may have any
<td><code>sandbox</code></td>
<td><code>String</code></td>
<td>
The content security policy used for sandboxed extension pages.
The content security policy used for the extension's <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/sandbox">sandboxed pages</a>.
</td>
</tr>
</tbody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ These are the `manifest.json` keys; these keys are available in Manifest V2 and
- [page_action](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/page_action) (Manifest V2 only in Chrome)
- [permissions](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions)
- [protocol_handlers](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/protocol_handlers) (Firefox only)
- [sandbox](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/sandbox)
- [short_name](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/short_name)
- [sidebar_action](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/sidebar_action)
- [storage](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/storage) (Not supported in Firefox)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
---
title: sandbox
slug: Mozilla/Add-ons/WebExtensions/manifest.json/sandbox
page-type: webextension-manifest-key
browser-compat: webextensions.manifest.sandbox
sidebar: addonsidebar
---

<table class="fullwidth-table standard-table">
<tbody>
<tr>
<th scope="row">Type</th>
<td><code>Object</code></td>
</tr>
<tr>
<th scope="row">Mandatory</th>
<td>No</td>
</tr>
<tr>
<th scope="row">Manifest version</th>
<td>2 or higher</td>
</tr>
<tr>
<th scope="row">Example</th>
<td>
<pre class="brush: json">
"sandbox": {
"pages": ["sandbox.html"]
}</pre>
</td>
</tr>
</tbody>
</table>

Use the `sandbox` key to designate one or more of an extension's pages as **sandboxed pages**.

Sandboxed pages are loaded with a unique, opaque origin, instead of the extension's usual `moz-extension://` origin. As a result:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link "opaque origin" to https://developer.mozilla.org/en-US/docs/Glossary/Origin#opaque_origin

Also add a bullet point mentioning that web platform APIs bound to the origin are unavailable. For some examples, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/sandbox#allow-same-origin

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


- Sandboxed pages can't access [WebExtension APIs](/en-US/docs/Mozilla/Add-ons/WebExtensions/API). The `browser` and `chrome` global objects are not available.
- Sandboxed pages can't access, and can't be accessed by, other pages in the extension, except by using {{DOMxRef("Window.postMessage()")}}.
Comment thread
rebloor marked this conversation as resolved.
Outdated

A sandboxed page can be given a more permissive [content security policy (CSP)](#content_security_policy_for_sandboxed_pages) than the rest of the extension. This includes a CSP that permits [`eval()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval) and similar constructs that are blocked by an extension's [default content security policy](/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_Security_Policy#default_content_security_policy). Because a sandboxed page can't use WebExtension APIs or reach the rest of the extension directly, this can be done without weakening the security of the extension as a whole.

This makes the `sandbox` key useful for including a third-party library that relies on `eval()` or `new Function()`, such as some templating engines: load the library in a sandboxed page, and use `postMessage()` to send it data from, and return results to, the rest of the extension.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The framing of template engine is likely copied from Chrome. Although that was a motivating factor back then (10+ years ago), it is hardly a relevant considerations now. These days such libraries are mostly designed to work even with a strict CSP. Let's drop the mention of templating libraries (the general reference to eval/Function are sufficient).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


## Manifest V2 syntax

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be less confusing if we:

  • declare one overview, and emphasize for the sandbox.content_security_policy key that it is MV2 only
  • at that description, point to the section on content_security_policy.sandbox (on the same page) for the MV3 syntax
  • note that the content_security_policy.sandbox is MV3-only, and that for MV2 the other key has to be used?

This would enable us to add new manifest keys to sandbox without being forced to duplicate that documentation in two sections. I anticipate that we will likely have a new manifest sub key in sandbox as part of https://bugzilla.mozilla.org/show_bug.cgi?id=2053336

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, done


In Manifest V2, `sandbox` is an object with these properties:

<table class="fullwidth-table standard-table">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Type</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>pages</code></td>
<td><code>Array</code> of <code>String</code></td>
<td>
Required. A list of paths, relative to manifest.json, to the extension's sandboxed pages.
</td>
</tr>
<tr>
<td><code>content_security_policy</code></td>
<td><code>String</code></td>
<td>
Optional. The content security policy applied to the sandboxed pages. See <a href="#content_security_policy_for_sandboxed_pages">Content security policy for sandboxed pages</a>.
</td>
</tr>
</tbody>
</table>

```json
"sandbox": {
"pages": ["sandbox.html"],
"content_security_policy": "sandbox allow-scripts; script-src 'self' 'unsafe-eval';"
}
```

## Manifest V3 syntax

In Manifest V3, `sandbox` only supports the `pages` property:

```json
"sandbox": {
"pages": ["sandbox.html"]
}
```

The content security policy for sandboxed pages is instead set using the `sandbox` property of the [`content_security_policy`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_security_policy) key:

```json
"content_security_policy": {
"sandbox": "sandbox allow-scripts; script-src 'self' 'unsafe-eval';"
}
```

## Content security policy for sandboxed pages

If a policy is not supplied, sandboxed pages get this default content security policy:

```plain
sandbox allow-scripts; script-src 'self';
```

This isolates a sandboxed page from the rest of the extension, but doesn't allow `eval()` or similar constructs. To permit these, include `'unsafe-eval'` (or `'wasm-unsafe-eval'` for [WebAssembly](/en-US/docs/WebAssembly)) in the `script-src` directive of a custom policy.
Comment thread
rebloor marked this conversation as resolved.
Outdated

> [!NOTE]
> Chrome has a more permissive default sandboxed pages CSP: `sandbox allow-scripts allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';`.
Comment thread
rebloor marked this conversation as resolved.
Outdated

Any custom policy supplied for sandboxed pages must meet these requirements:

- It must include the {{CSP("sandbox")}} directive.
- The {{CSP("sandbox")}} directive must not include the `allow-same-origin` keyword. Allowing this would give the page access to the rest of the extension's origin, defeating the purpose of sandboxing it.

## Example

This example loads a third-party templating library that uses `eval()`-like constructs into a sandboxed page, and uses it from a popup.

`manifest.json`:

```json
{
"manifest_version": 3,
"name": "Sandbox example",
"version": "1.0",
"action": {
"default_popup": "popup.html"
},
"sandbox": {
"pages": ["sandbox.html"]
},
"content_security_policy": {
"sandbox": "sandbox allow-scripts; script-src 'self' 'unsafe-eval';"
}
}
```

`sandbox.html`:

```html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script src="templating-library.js"></script>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intended as a placeholder example? The example on the page itself does not run because the definition of the file is missing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's now a fully working example. However, after debugging an issue I found with Claude, it responded that "sandbox.js rejected every message with if (event.origin !== location.origin) — but a sandboxed page has an opaque origin (serializes to "null"), while the sender (popup.html) has a real moz-extension:// origin, so that check could never pass and the render would never happen. I replaced it with event.source !== window.parent (and added the matching check on the popup.js side, event.source !== sandbox.contentWindow), which validates the sender by window identity instead of origin — this is what MDN's own postMessage() security-concerns guidance recommends specifically because origin comparisons don't work for opaque-origin frames."

<script src="sandbox.js"></script>
</head>
<body></body>
</html>
```

`sandbox.js` listens for messages from the popup, renders a template using the sandboxed library, and posts the result back:

```js
window.addEventListener("message", (event) => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Below I am showing a concrete snippet to validate messages. Can you include that here too, and prominently mention a link to the security-relevant best practices at https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#security_concerns

Ideally we should have a dedicated section on this manifest page that clarifies how this feature should be used:

  • messages between the extension and sandboxed page should be strictly validated, with link to https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#security_concerns
  • don't execute untrusted code. Although the extension does not have access to privileged APIs, the extension URL may identify the use of the extension and be abused for fingerprinting purposes.
  • don't use sandboxed pages with a relaxed CSP if your only objective is the use of WebAssembly. Instead, add 'wasm-unsafe-eval' to the extension's content_security_policy instead.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

const { template, context } = event.data;
const render = TemplatingLibrary.compile(template);
event.source.postMessage({ result: render(context) }, event.origin);
});
```

`popup.html` embeds the sandboxed page in a hidden iframe:

```html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script src="popup.js"></script>
</head>
<body>
<iframe id="sandbox" src="sandbox.html" hidden></iframe>
</body>
</html>
```

`popup.js` sends data to the sandboxed page and handles the result:

```js
const sandbox = document.getElementById("sandbox");

sandbox.addEventListener("load", () => {
sandbox.contentWindow.postMessage(
{ template: "Hello, {{name}}!", context: { name: "world" } },
"*",
);
});

window.addEventListener("message", (event) => {
Comment thread
rebloor marked this conversation as resolved.
console.log(event.data.result);
});
```

## Browser compatibility

{{Compat}}
4 changes: 1 addition & 3 deletions files/en-us/mozilla/firefox/releases/154/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,7 @@ Firefox 154 is the current [Nightly version of Firefox](https://www.firefox.com/

## Changes for add-on developers

<!-- ### Removals -->

<!-- ### Other -->
- Adds support for the [`sandbox`](/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/sandbox) manifest key, enabling extensions to designate pages that load with an opaque origin. A sandboxed page can use `eval()` and similar constructs that are otherwise blocked by the extension's [content security policy](/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_Security_Policy). The sandboxed page can only access WebExtension APIs or the rest of the extension through {{domxref("Window.postMessage()")}}. ([Firefox bug 1685123](https://bugzil.la/1685123))
Comment thread
rebloor marked this conversation as resolved.
Outdated

## Experimental web features

Expand Down