Automated detection of cross-mechanism security policy conflicts in web applications — including Shadow DOM boundary penetration.
CSP Bypass Detector is a research tool that systematically analyzes Content Security Policy (CSP) configurations and their interactions with other web security mechanisms — including COOP, COEP, Trusted Types, SRI, CORP, and Shadow DOM — to discover cross-mechanism conflicts and policy boundary violations that no existing tool identifies.
Builds a Z3 SMT formal model of 7 web security mechanisms. 7 theoretically possible conflicts identified, 4 confirmed in the wild across Google and Meta properties, affecting 16 sites (6.8% of CSP-enabled) in the Tranco Top 1000.
| Conflict | Mechanisms | Confirmed | Affected |
|---|---|---|---|
| C-X2 | COOP same-origin + missing frame-ancestors | welt.de | 1 site |
| C-X3 | Trusted Types + unsafe-inline | Google (YouTube, Analytics) | 8 sites |
| C-X4 | Trusted Types + strict-dynamic | Google (YouTube, Analytics) | 7 sites |
| C-X5 | CORP same-origin + cross-origin scripts | Meta (Facebook, Instagram) | 7 sites |
Formal analysis of how CSP/Trusted Types propagate across Shadow DOM boundaries — a gap in the current W3C specifications. An Information Flow Control (IFC) model identifies 5 potential conflicts, 4 empirically confirmed via Playwright experiments on Chromium.
| Conflict | Type | Status |
|---|---|---|
| C5-C1 | Open shadow inherits main CSP | ✅ SAFE (confirmed) |
| C5-C2 | TT policy created inside shadow affects main document | 🔴 CONFIRMED |
| C5-C3 | Slot-based content crosses policy boundary | 🔴 CONFIRMED |
| C5-C4 | Declarative Shadow DOM timing issue | 🔴 CONFIRMED |
| C5-C5 | Closed shadow event retargeting leaks data | 🔴 CONFIRMED |
| Metric | Value |
|---|---|
| Sites with CSP | 260 (26.0%) |
| Sites with Shadow DOM | 17 (1.7%) |
| Both CSP + Shadow DOM | 12 (4.6% of CSP) |
| Top Shadow DOM user | redhat.com — 229 shadow roots + unsafe-inline CSP |
| Missing frame-ancestors | nytimes.com, archive.org (30+ roots each) |
# Install
pip install -e .
playwright install chromium
# Scan a single site
csp-scan scan https://example.com
# HTML report
csp-scan scan https://example.com --html
# Batch scan
csp-scan batch --input domains.txt --output results/30 detection types across 5 classes. 19 types unique to this tool.
| Class | Types | Severity | Description |
|---|---|---|---|
| B: Policy Design | B1-B7 | 3-5 | unsafe-inline, nonce reuse, hash entropy, missing directives |
| C: Cross-mechanism | C1-C4, C-X2–C-X7 | 2-5 | CORS/COOP/COEP/TT interactions, Z3-confirmed conflicts |
| C5: Shadow DOM | C5a–C5e | 2-4 | Shadow boundary penetration, closed shadow detection, slot injection |
# Run the Shadow DOM prevalence scan
python scripts/phase3_scan.py
# Or scan a single site with full detection
csp-scan scan https://redhat.com --htmlThe Playwright-based crawler detects:
- Open and closed shadow roots
- Custom elements (potential closed shadow hosts)
- Slot usage patterns
- TrustedTypes policy creation inside shadow roots
Live PoC pages for 4 confirmed conflict types:
cd docs/pocs
python server.py
# Open http://localhost:8000| PoC | URL |
|---|---|
| C-X2: COOP + frame clickjacking | /c-x2/attacker |
| C-X3: TT + unsafe-inline bypass | /c-x3/ |
| C-X4: TT + strict-dynamic bypass | /c-x4/ |
| C-X5: CORP + SRI integrity failure | /c-x5/ |
| Metric | CSPE | Our Tool |
|---|---|---|
| Detection types | 8 categories | 30 types |
| Cross-mechanism conflicts | ❌ | ✅ 16 sites (23 instances) |
| Shadow DOM boundary detection | ❌ | ✅ 4 confirmed conflicts |
| Sites flagged (of 260 CSP) | 236 (99.6%) | 232 (97.9%) |
| Agreement | — | 97.5% |
| Metric | Value |
|---|---|
| Precision | 100.0% |
| Recall | 96.7% |
| F1 Score | 0.983 |
| Metric | Without Model | With Model | Improvement |
|---|---|---|---|
| Sites with findings | 216 (91.1%) | 232 (97.9%) | +16 sites |
| Total findings | 868 | 891 | +23 (2.6%) |
| Detection classes | 4 | 5 (added C-X) | +1 class |
csp_byspass_detector/
├── engine/
│ ├── module_b_policy.py # Policy design checks
│ ├── module_c_cross_mechanism.py # Cross-mechanism C-X conflicts
│ └── module_c5_shadow_dom.py # Shadow DOM boundary detection
├── models/
│ ├── z3_checker.py # Z3 cross-mechanism model (7/7 SAT)
│ └── ifc_model.py # Z3 IFC Shadow DOM model (4/5 SAT)
├── verifier/
│ ├── active_verifier.py # Playwright verification
│ └── shadow_monitor.py # Shadow DOM API monitoring
├── collector/
│ └── crawler.py # CSP + Shadow DOM collection
└── evaluation/
├── baseline.py # CSPE/Observatory comparison
├── ground_truth.py # Annotation framework
└── metrics.py # Precision/Recall/F1
scripts/
├── phase3_scan.py # Tranco 1K prevalence scan
├── fuzzer.py # Grammar-based fuzzer
├── spec_experiments.py # Playwright empirical experiments
└── shadow_dom_test.py # Shadow DOM detection verification
docs/
├── conflict-analysis.md # C-X conflict analysis
├── ablation-study.md # Formal model impact
├── ground-truth-report.md # Precision/Recall analysis
├── research-plan.md # Research roadmap
├── pocs/ # Live PoC demonstrations
└── literature/
├── core-papers-notes.md # DiffCSP, WebSpec, Block Party
└── spec-notes.md # W3C CSP + Shadow DOM spec analysis
During Phase 1 development, we discovered that Playwright's page.setContent() method does not correctly enforce CSP meta tags. All CSP-related experiments must use page.goto() with real HTML files or a local HTTP server for reliable results. This is a documented methodological limitation.
python -m pytest tests/ -vMIT License