Skip to main content

EXT-003 Extension CSP allows remote code load

The Content Security Policy in a browser extension's manifest constrains what scripts the extension can run. A CSP that permits unsafe-eval inside a script-src directive lets the extension call eval(), new Function(), and similar runtime-string-to-code primitives. A CSP that permits unsafe-inline lets the extension execute scripts injected into a page at runtime. Either is effectively a remote-code- load primitive: static review of the extension's bundle never sees the payload because the payload is built or fetched at runtime.

A publisher compromise of an extension with this CSP reaches every user the next time they open the browser.

What Vulkro detects

Rule fires when an extension's manifest content_security_policy contains unsafe-eval or unsafe-inline AND the keyword sits inside a script-src or default-src directive. (Manifest V3 nests CSP under extension_pages / sandbox; the parser collapses both into a single scan string so the same check covers MV2 and MV3.)

unsafe-inline inside a style-src directive does NOT fire: runtime-styled CSS is not a remote-code-load primitive in this threat model.

Severity: High. Confidence: High. Evidence signal: extension-remote-code-load-csp, weight 0.9, source Pattern.

Non-compliant manifest (Manifest V2 form)

{
"manifest_version": 2,
"name": "Inline-friendly tool",
"version": "1.0.0",
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
}

Non-compliant manifest (Manifest V3 form)

{
"manifest_version": 3,
"name": "Inline-friendly tool",
"version": "1.0.0",
"content_security_policy": {
"extension_pages": "script-src 'self' 'unsafe-inline'; object-src 'self'"
}
}

Both let the extension execute string-to-code at runtime. A publisher account compromise can push an update whose payload the marketplace's static review never saw.

Compliant manifest

{
"manifest_version": 3,
"name": "Inline-friendly tool",
"version": "1.0.0",
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'"
}
}

'self' only: the extension can only execute scripts bundled inside its own package, which marketplace review reads at publish time.

Remediation

  1. Replace the permissive CSP with the marketplace default: script-src 'self'; object-src 'self'. This is the value Chrome and Firefox bake in when no CSP is declared, and the value extensions should keep unless they have an explicit reason to widen it.
  2. If the extension genuinely needs to evaluate runtime- generated code (a sandboxed live-coding tool, a notebook- style UI), bundle the evaluator. Ship a complete interpreter inside the extension rather than asking the browser to permit string-to-code.
  3. If the extension needs third-party scripts, list each host explicitly in script-src. A surgical allowlist (script-src 'self' https://cdn.example.com/) is reviewable; unsafe-eval is not.
  4. When auditing a third-party extension, treat an unsafe-eval CSP as equivalent to a remote-code-load primitive. A publisher compromise reaches every user the next time they open the browser.

See also

References