Commit a4b2fc7c
| SHA | a4b2fc7ca89c7916a32a3e279ab3880ebaa7a734 |
|---|---|
| Author | MohamedBassem <me at mbassem dot com> |
| Author Date | 2025-08-23 16:03 +0300 |
| Committer | MohamedBassem <me at mbassem dot com> |
| Commit Date | 2025-08-23 16:03 +0300 |
| Parent(s) | 096af7efffe1 (diff) |
| Tree | 0697484b3881 |
fix(security): Add CSP policies on asset serving path
| File | + | - | Graph | |
|---|---|---|---|---|
| M | apps/web/components/dashboard/preview/LinkContentSection.tsx | +1 | -0 |
|
| M | packages/api/utils/assets.ts | +19 | -2 |
|
2 file(s) changed, 20 insertions(+), 2 deletions(-)
apps/web/components/dashboard/preview/LinkContentSection.tsx
diff --git a/apps/web/components/dashboard/preview/LinkContentSection.tsx b/apps/web/components/dashboard/preview/LinkContentSection.tsx index 67de4e75..a0a6f580 100644 --- a/apps/web/components/dashboard/preview/LinkContentSection.tsx +++ b/apps/web/components/dashboard/preview/LinkContentSection.tsx @@ -62,6 +62,7 @@ function FullPageArchiveSection({ link }: { link: ZBookmarkedLink }) { link.fullPageArchiveAssetId ?? link.precrawledArchiveAssetId; return ( <iframe + sandbox="" title={link.url} src={`/api/assets/${archiveAssetId}`} className="relative h-full min-w-full"
packages/api/utils/assets.ts
diff --git a/packages/api/utils/assets.ts b/packages/api/utils/assets.ts index 205e1a76..3da32ff2 100644 --- a/packages/api/utils/assets.ts +++ b/packages/api/utils/assets.ts @@ -22,6 +22,25 @@ export async function serveAsset(c: Context, assetId: string, userId: string) { }), ]); + // Default Headers + c.header("Content-type", metadata.contentType); + c.header("X-Content-Type-Options", "nosniff"); + c.header( + "Content-Security-Policy", + [ + "sandbox", + "default-src 'none'", + "base-uri 'none'", + "form-action 'none'", + "img-src https: data: blob:", + "style-src 'unsafe-inline' https:", + "connect-src 'none'", + "media-src https: data: blob:", + "object-src 'none'", + "frame-src 'none'", + ].join("; "), + ); + const range = c.req.header("Range"); if (range) { const parts = range.replace(/bytes=/, "").split("-"); @@ -38,7 +57,6 @@ export async function serveAsset(c: Context, assetId: string, userId: string) { c.header("Content-Range", `bytes ${start}-${end}/${size}`); c.header("Accept-Ranges", "bytes"); c.header("Content-Length", (end - start + 1).toString()); - c.header("Content-type", metadata.contentType); return stream(c, async (stream) => { await stream.pipe(toWebReadableStream(fStream)); }); @@ -49,7 +67,6 @@ export async function serveAsset(c: Context, assetId: string, userId: string) { }); c.status(200); c.header("Content-Length", size.toString()); - c.header("Content-type", metadata.contentType); return stream(c, async (stream) => { await stream.pipe(toWebReadableStream(fStream)); });