What is blob: & why avoid it in CSP ?

Wednesday, February 11, 2026
5 min read
Theotime QuereCentralCSP Team
The blob: scheme in Content Security Policy allows resources to be loaded from URLs created by the Blob API, typically in-memory or temporary URLs that JavaScript creates at runtime. Allowing blob: in script or style directives can undermine CSP by letting the page execute or apply dynamically constructed code. This article explains the risks and how to remove or restrict blob: to mitigate them.

What Is the blob: Scheme?

A blob URL (e.g. blob:https://example.com/uuid) is a URL that refers to a Blob or File object in the browser. Scripts can create such URLs and use them in <script src="...">, <link href="...">, workers, or other APIs. CSP can allow or block these via source lists such as script-src 'self' blob:.

A classic use of blob: URLs — enabling users to download in-memory generated files without any server round-trip.

Content-Security-Policy: script-src 'self' blob:;

<!-- Example: Create a blob URL for downloading a text file -->
<script>
  // Prepare some text to download as a file
  const textData = "Hello, world! This file was generated in the browser.";
  const blob = new Blob([textData], { type: "text/plain" });
  const blobUrl = URL.createObjectURL(blob);

  // Create a link for download
  const a = document.createElement('a');
  a.href = blobUrl;
  a.download = "hello.txt";
  a.textContent = "Download file";
  document.body.appendChild(a);
</script>

Classic use: Calculating the sum of numbers in a Web Worker loaded via a blob: URL — demonstrates functional, legitimate use of blob for background tasks.

Content-Security-Policy: script-src 'self' blob:;

<!-- Classic example: using a blob: URL to run a Web Worker performing a calculation -->
<script>
// Worker code that sums an array sent from the main thread
const workerCode = `
  self.onmessage = function(event) {
    // Receive array, sum it
    const numbers = event.data;
    const sum = numbers.reduce((acc, value) => acc + value, 0);
    // Send result back
    postMessage(sum);
  };
`;
// Create a blob and a blob URL
const workerBlob = new Blob([workerCode], { type: "application/javascript" });
const workerBlobUrl = URL.createObjectURL(workerBlob);

// Create the worker from blob: URL
const worker = new Worker(workerBlobUrl);

// Send array to worker; receive the sum
worker.onmessage = function(event) {
  alert("Sum calculated by the worker: " + event.data); // e.g., alerts "Sum calculated by the worker: 15"
}
worker.postMessage([1, 2, 3, 4, 5]);
</script>

Common Use Cases

Common use cases of blob URLs include:
  • Media : Playing audio or video from in-memory or recorded data (e.g. media-src).
  • Downloads : Generating files for the user to download (often not script/style).
  • Workers : Loading a worker script from a blob URL (e.g. worker-src or child-src).
Where blob: becomes dangerous when it can execute arbitrary code. Any script on the page can create a blob containing arbitrary JavaScript or CSS and load it via a blob URL. That is effectively dynamic code execution, similar to eval or inline scripts, and can defeat the purpose of CSP.

Security Vulnerabilities

When blob: is allowed in script-src (or style-src):
  1. Bypass of script/style restrictions : If an attacker can run script (e.g. via XSS or a compromised dependency), they can build a blob with malicious content, create a blob URL, and load it in a <script> or <link>. CSP would allow it because the source is blob:, not because the content was approved.
  2. No integrity or allowlist : Blob URLs are opaque and short-lived. You cannot allowlist them by host or hash. Allowing blob: in script-src or style-src is a broad permission for any script on the page to load arbitrary code.
  3. Harder to audit : Unlike static files or inline blocks, blob content is generated at runtime, so it's difficult to review or correlate with violation reports.
For worker-src, media-src, or img-src, the risk profile depends on what you allow: worker blobs can still run script, so restrict worker-src carefully. Media and image blobs don't execute script but can still be abused for data exfiltration or unexpected behavior if too permissive.

How allowing blob: in script-src lets runtime scripts run arbitrary code by creating script tags loading blob: URLs.

Content-Security-Policy: script-src 'self' blob:;

<!-- Dangerous: any script on the page can create and execute a blob: URL -->
<script>
// Create a malicious JS payload
const code = "alert('Blob XSS: ' + document.domain)";
const blob = new Blob([code], { type: "text/javascript" });
const blobUrl = URL.createObjectURL(blob);
// Dynamically load the payload as a script tag
const s = document.createElement('script');
s.src = blobUrl;
document.body.appendChild(s);
</script>

How allowing blob: in script-src enables runtime creation and execution of malicious workers via blob URLs.

Content-Security-Policy: script-src 'self' blob:;

<!-- Example: Blob URL used in a Worker (can execute attacker JavaScript) -->
<script>
// Malicious code for the worker
const workerCode = "postMessage('XSS from worker: ' + self.origin)";
const workerBlob = new Blob([workerCode], { type: "application/javascript" });
const workerBlobUrl = URL.createObjectURL(workerBlob);
// Instantiating the Worker from a blob: URL
const w = new Worker(workerBlobUrl);
w.onmessage = function(event) {
  // Show the message from the malicious worker
  alert(event.data);
};
</script>

How to Remove or Restrict blob:

  1. Move scripts and styles off blob: URLs : Serve scripts and styles from your origin or a trusted CDN. Use nonces or hashes in CSP to allow only the scripts you intend. For workers, prefer serving worker scripts from static URLs (e.g. /workers/task.js) instead of creating them from blobs at runtime.
  2. Tighten directives : Remove blob: from the sensible directives of the CSP.If you must use it, keep it out of any directive that affects script or style execution.
  3. Test with report-only : Use Content-Security-Policy-Report-Only and reporting to see what would break. Fix legitimate uses by serving resources from proper URLs or static worker scripts, then switch to enforce mode without blob: in script or style directives.

How to safely load scripts, styles, and workers without using blob: in sensible directives.

Content-Security-Policy: script-src 'self'; style-src 'self'; worker-src 'self'; media-src 'self' blob:;

<!-- Scripts and styles from your own origin -->
<script src="/static/js/app.js"></script>

<!-- Worker loaded from a static URL instead of a blob: -->
<script>
const worker = new Worker('/static/workers/task.js');
worker.postMessage({ data: [1, 2, 3, 4, 5] });
</script>
Using the Scanner and CSP Builder can help you see what your site currently allows and generate a policy that avoids insecure blob: use.

See also

    What is blob: & why avoid it in CSP ?