Third-Party Script Audit
Every third-party <script>, font, widget, or embed is a data-access
grant to a vendor and a supply-chain dependency the site doesn't control.
This skill inventories what's actually loaded, checks it against what's
declared (CSP), and flags what's missing the one mitigation available for
mutable third-party code (SRI).
Works on any website — the audit is entirely observational (network
requests + response headers), no special access needed.
When not to use this
- Server-side dependency vulnerabilities (npm/pip packages) →
npm audit, pip-audit, or a dedicated security-baseline skill. This skill
only looks at what a browser actually fetches from third-party origins.
- Full penetration testing → out of scope entirely; this is a
factual inventory, not an attack simulation.
- Deciding whether the site's data collection is GDPR-compliant →
pair with
gdpr-test-patterns or route to the person responsible for
that legal judgment. This skill answers "what is actually being sent
where", not "is that lawful".
Phase 0 — Inventory
For each sampled page (reuse the page set from responsive-visual-review
if a recent run exists), capture every network request the page makes
while loading and interacting normally:
- Playwright MCP
browser_network_requests, or page.on('request') in a
short script if no MCP tool is available.
- List every request whose origin is NOT the site's own domain or its own
CDN/asset host.
Phase 1 — Classify
For each distinct third-party origin found:
- What is it — analytics, web font, chat/support widget, ad network,
payment/consent widget (e.g. Turnstile), CDN-hosted library, embedded
media (YouTube, Vimeo)?
- What can it plausibly collect — does it set cookies, use
fingerprinting-capable APIs, receive PII in URL query params or POST
bodies (check what data the page actually sends it, not just that it's
loaded)?
- Is it already declared — cross-check against the site's CSP
allowlist (
_headers, meta CSP tag, or server-set header) if one
exists. An origin loading without being in the allowlist either means
the CSP is misconfigured (too permissive, e.g. a wildcard) or the
browser should be blocking it — check which.
Phase 2 — SRI check
For every <script>/<link> served from a third-party origin at a
static, versioned URL, check for integrity + crossorigin attributes.
- Flag any missing SRI on a script the vendor supports SRI for (most
CDN-hosted libraries with pinned versions do).
- Note, don't flag, the known legitimate exceptions: some vendors (Google
Fonts CSS endpoint, most analytics beacons, most chat-widget loaders)
serve dynamic/personalized responses that can't have a static SRI hash
— that's an accepted limitation, not a finding.
Phase 3 — CSP drift check
If the site has a CSP, diff the allowlist against what Phase 0 actually
observed:
- Under-permissive (missing entries): would break in a stricter
browser or a future CSP tightening — though if the resource loads fine
today, this usually means the CSP is more permissive elsewhere
(
unsafe-inline, a broad https: source) than it looks.
- Over-permissive (stale entries): origins allowlisted but no longer
actually loaded anywhere in the sampled pages — safe to remove, reduces
attack surface.
Phase 4 — Findings
| Severity |
Examples |
| Critical |
PII sent to an undisclosed third party, or a CSP wildcard/unsafe-eval allowing arbitrary script origins |
| High |
Missing SRI on a mutable, vendor-SRI-supported third-party script |
| Medium |
CSP allowlist drift (stale entries, or an origin loading outside the declared allowlist) |
| Low |
A legitimate, documented SRI exception worth noting for future reference (not a real gap) |
Report the full origin inventory alongside the findings — even entries
with no issue are useful groundwork for the next audit and for whoever
owns the GDPR/consent review.
1---2name: third-party-script-audit3description: Inventories every third-party script and resource a website loads (analytics, fonts, chat widgets, ads, embeds) and checks what each one can access, whether Subresource Integrity (SRI) is present and correct, and whether the site's CSP allowlist actually matches what's really loaded — no more, no less. Works on any website. Trigger on "audit third-party scripts", "what data are we leaking to vendors", "check SRI", "review our CSP allowlist", or before/after adding a new embedded widget or script. NOT a full penetration test or server-side dependency-vulnerability scan (use npm audit/pip-audit/a security-baseline skill for that — this is about what loads IN THE BROWSER from external origins, not server-side packages). NOT a standalone GDPR/consent-banner completeness check (pair with gdpr-test-patterns for the legal-basis/consent angle — this skill supplies the factual inventory a GDPR review needs, it doesn't make the legal judgment itself).4---56# Third-Party Script Audit78Every third-party `<script>`, font, widget, or embed is a data-access9grant to a vendor and a supply-chain dependency the site doesn't control.10This skill inventories what's actually loaded, checks it against what's11declared (CSP), and flags what's missing the one mitigation available for12mutable third-party code (SRI).1314Works on any website — the audit is entirely observational (network15requests + response headers), no special access needed.1617## When not to use this1819- **Server-side dependency vulnerabilities** (npm/pip packages) → `npm20 audit`, `pip-audit`, or a dedicated security-baseline skill. This skill21 only looks at what a browser actually fetches from third-party origins.22- **Full penetration testing** → out of scope entirely; this is a23 factual inventory, not an attack simulation.24- **Deciding whether the site's data collection is GDPR-compliant** →25 pair with `gdpr-test-patterns` or route to the person responsible for26 that legal judgment. This skill answers "what is actually being sent27 where", not "is that lawful".2829## Phase 0 — Inventory3031For each sampled page (reuse the page set from `responsive-visual-review`32if a recent run exists), capture every network request the page makes33while loading and interacting normally:34- Playwright MCP `browser_network_requests`, or `page.on('request')` in a35 short script if no MCP tool is available.36- List every request whose origin is NOT the site's own domain or its own37 CDN/asset host.3839## Phase 1 — Classify4041For each distinct third-party origin found:42- **What is it** — analytics, web font, chat/support widget, ad network,43 payment/consent widget (e.g. Turnstile), CDN-hosted library, embedded44 media (YouTube, Vimeo)?45- **What can it plausibly collect** — does it set cookies, use46 fingerprinting-capable APIs, receive PII in URL query params or POST47 bodies (check what data the page actually sends it, not just that it's48 loaded)?49- **Is it already declared** — cross-check against the site's CSP50 allowlist (`_headers`, meta CSP tag, or server-set header) if one51 exists. An origin loading without being in the allowlist either means52 the CSP is misconfigured (too permissive, e.g. a wildcard) or the53 browser should be blocking it — check which.5455## Phase 2 — SRI check5657For every `<script>`/`<link>` served from a third-party origin at a58static, versioned URL, check for `integrity` + `crossorigin` attributes.59- Flag any missing SRI on a script the vendor supports SRI for (most60 CDN-hosted libraries with pinned versions do).61- Note, don't flag, the known legitimate exceptions: some vendors (Google62 Fonts CSS endpoint, most analytics beacons, most chat-widget loaders)63 serve dynamic/personalized responses that can't have a static SRI hash64 — that's an accepted limitation, not a finding.6566## Phase 3 — CSP drift check6768If the site has a CSP, diff the allowlist against what Phase 0 actually69observed:70- **Under-permissive** (missing entries): would break in a stricter71 browser or a future CSP tightening — though if the resource loads fine72 today, this usually means the CSP is more permissive elsewhere73 (`unsafe-inline`, a broad `https:` source) than it looks.74- **Over-permissive** (stale entries): origins allowlisted but no longer75 actually loaded anywhere in the sampled pages — safe to remove, reduces76 attack surface.7778## Phase 4 — Findings7980| Severity | Examples |81|----------|----------|82| Critical | PII sent to an undisclosed third party, or a CSP wildcard/`unsafe-eval` allowing arbitrary script origins |83| High | Missing SRI on a mutable, vendor-SRI-supported third-party script |84| Medium | CSP allowlist drift (stale entries, or an origin loading outside the declared allowlist) |85| Low | A legitimate, documented SRI exception worth noting for future reference (not a real gap) |8687Report the full origin inventory alongside the findings — even entries88with no issue are useful groundwork for the next audit and for whoever89owns the GDPR/consent review.