From a8093975fdefd9444ba9279d809769549dd9246f Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Tue, 6 Jan 2026 09:07:21 +1100 Subject: [PATCH] Fix bug in mode, which would inject the CSP into third party domains, which they would then throw violations for and trip the result --- CHANGELOG.md | 4 ++++ pyproject.toml | 2 +- src/cspresso/crawl.py | 14 ++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66ca668..3dbecde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.3 + + * Fix bug in `--evaluate` mode, which would inject the CSP into third party domains, which they would then throw violations for and trip the result + ## 0.1.2 * Add `--bypass-csp` option to ignore an existing enforcing CSP to avoid it skewing results diff --git a/pyproject.toml b/pyproject.toml index 5c29369..d6fcf69 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "cspresso" -version = "0.1.2" +version = "0.1.3" description = "Crawl a website with a headless browser and generate a draft Content-Security-Policy (CSP)." authors = ["Miguel Jacq "] readme = "README.md" diff --git a/src/cspresso/crawl.py b/src/cspresso/crawl.py index 44c96ad..a669f2c 100644 --- a/src/cspresso/crawl.py +++ b/src/cspresso/crawl.py @@ -362,9 +362,23 @@ async def crawl_and_generate_csp( if request.resource_type != "document": return await route.continue_() + # IMPORTANT: Don't rewrite CSP on third-party iframe/object documents. + # Otherwise --evaluate / --bypass-csp will mutate embedded origins + # (e.g. asciinema.org) and produce bogus frame-ancestors violations. + req_origin = origin_of(request.url) + if not req_origin or req_origin != base_origin: + return await route.continue_() + resp = await route.fetch() hdrs = {k.lower(): v for k, v in (resp.headers or {}).items()} + # Only treat actual HTML documents as candidates for CSP header rewriting. + # (Playwright classifies iframe navigations as "document" even when non-HTML.) + ct = (hdrs.get("content-type") or "").lower() + is_html = ("text/html" in ct) or ("application/xhtml+xml" in ct) + if not is_html: + return await route.fulfill(response=resp) + if bypass_csp: hdrs.pop("content-security-policy", None) hdrs.pop("content-security-policy-report-only", None)