Skip to content

Commit 34b0fc2

Browse files
Copilotrichard-to
andauthored
Add blob: support to default CSP frame-src policy (#1336)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: richard-to <539889+richard-to@users.noreply.github.com>
1 parent 98386ff commit 34b0fc2

8 files changed

+64
-7
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import mesop as me
2+
3+
4+
@me.page(path="/testing/blob_iframe", title="Blob iframe test")
5+
def page():
6+
me.text("Testing blob iframe support")
7+
# This will create an iframe with a blob URL using inline JavaScript
8+
me.html(
9+
"""
10+
<div id="blob-iframe-container">
11+
<script>
12+
// Create a blob URL and set it as iframe src
13+
const content = '<html><body><h1>Blob iframe content</h1></body></html>';
14+
const blob = new Blob([content], {type: 'text/html'});
15+
const blobUrl = URL.createObjectURL(blob);
16+
const iframe = document.createElement('iframe');
17+
iframe.src = blobUrl;
18+
iframe.id = 'test-blob-iframe';
19+
// Revoke the blob URL after the iframe loads to prevent memory leak
20+
iframe.onload = () => URL.revokeObjectURL(blobUrl);
21+
document.getElementById('blob-iframe-container').appendChild(iframe);
22+
</script>
23+
</div>
24+
"""
25+
)

mesop/server/static_file_serving.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,8 @@ def add_security_headers(response: Response):
253253
{
254254
"default-src": "'self'",
255255
"font-src": "'self' fonts.gstatic.com data:",
256-
# Mesop app developers should be able to iframe other sites.
257-
"frame-src": "*",
256+
# Mesop app developers should be able to iframe other sites from various origins.
257+
"frame-src": "* blob:",
258258
# Mesop app developers should be able to load images and media from various origins.
259259
"img-src": "'self' data: https: http: blob:",
260260
"media-src": "'self' data: https: blob:",
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import {expect} from '@playwright/test';
2+
import {testInProdOnly} from './e2e_helpers';
3+
4+
testInProdOnly('CSP frame-src includes blob', async ({page}) => {
5+
// Listen for CSP violations before navigating
6+
const cspErrors: string[] = [];
7+
page.on('console', (msg) => {
8+
if (
9+
msg.type() === 'error' &&
10+
msg.text().includes('Content Security Policy')
11+
) {
12+
cspErrors.push(msg.text());
13+
}
14+
});
15+
16+
// Get the CSP header from the response
17+
const response = await page.goto('/testing/blob_iframe');
18+
const headers = response?.headers();
19+
const cspHeader = headers?.['content-security-policy'];
20+
21+
// Verify CSP header is present
22+
expect(cspHeader).toBeDefined();
23+
24+
// Verify frame-src directive includes blob:
25+
expect(cspHeader).toContain('frame-src');
26+
expect(cspHeader).toMatch(/frame-src[^;]*blob:/);
27+
28+
await page.waitForLoadState('networkidle');
29+
30+
// No CSP violations should be present
31+
expect(cspErrors).toHaveLength(0);
32+
});

mesop/tests/e2e/snapshots/web_security_test.ts_csp-allowed-font-srcs.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
default-src 'self'
22
font-src 'self' fonts.gstatic.com data: fontsrc1 fontsrc2
3-
frame-src *
3+
frame-src * blob:
44
img-src 'self' data: https: http: blob:
55
media-src 'self' data: https: blob:
66
style-src 'self' 'unsafe-inline' fonts.googleapis.com

mesop/tests/e2e/snapshots/web_security_test.ts_csp-allowed-iframe-parents.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
default-src 'self'
22
font-src 'self' fonts.gstatic.com data:
3-
frame-src *
3+
frame-src * blob:
44
img-src 'self' data: https: http: blob:
55
media-src 'self' data: https: blob:
66
style-src 'self' 'unsafe-inline' fonts.googleapis.com

mesop/tests/e2e/snapshots/web_security_test.ts_csp-escaping.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
default-src 'self'
22
font-src 'self' fonts.gstatic.com data:
3-
frame-src *
3+
frame-src * blob:
44
img-src 'self' data: https: http: blob:
55
media-src 'self' data: https: blob:
66
style-src 'self' 'unsafe-inline' fonts.googleapis.com http://google.com/stylesheets%2C1%3B2

mesop/tests/e2e/snapshots/web_security_test.ts_csp-trusted-types.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
default-src 'self'
22
font-src 'self' fonts.gstatic.com data:
3-
frame-src *
3+
frame-src * blob:
44
img-src 'self' data: https: http: blob:
55
media-src 'self' data: https: blob:
66
style-src 'self' 'unsafe-inline' fonts.googleapis.com

mesop/tests/e2e/snapshots/web_security_test.ts_csp.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
default-src 'self'
22
font-src 'self' fonts.gstatic.com data:
3-
frame-src *
3+
frame-src * blob:
44
img-src 'self' data: https: http: blob:
55
media-src 'self' data: https: blob:
66
style-src 'self' 'unsafe-inline' fonts.googleapis.com

0 commit comments

Comments
 (0)