Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Magical Client-side Logging — NDC Oslo 2026

Magical Client-side Logging — NDC Oslo 2026

In a server-side app, it's fairly easy to find out what went wrong from logs. But what about the client side, where you don't have the luxury of consistency or reliable controls in an often hostile environment? The W3C's Reporting API and associated HTTP headers can let you know about all kinds of client-side issues that you'd otherwise never see. Reveal problems related to content security policy, network error logging, CSP hashes (give your SBOMs a workout!), permissions policy, and even browser crashes.

The standards covering these useful features are in a state of flux, and suffer from inconsistent implementation across browsers, so I'll guide you through what works, what doesn't, how to make them all work everywhere, and how to use aggregation services to make sense of all the new data you're getting.

We'll put it all together, and solve all the issues that only your customers have been seeing!

Avatar for Marcus Bointon

Marcus Bointon

September 18, 2026

More Decks by Marcus Bointon

Other Decks in Technology

Transcript

  1. Marcus Bointon Skier Songwriter Author of "The HTTP/3 Book" PHPMailer

    maintainer, Laravel dev Radically Open Security Pentests, code audits
  2. BAD STUFF HAPPENS — ON THE SERVER • Consistent, uniform,

    environment • Invisible to clients • All in one place, no loss • Easy to inspect & monitor Marcus Bointon — Magical client-side logging NDC Oslo 2026
  3. BAD STUFF HAPPENS — ON THE CLIENT • Billions of

    crazily different, inconsistent, possibly malicious con gurations • JS- and network-hostile environment • Errors visible to clients • Invisible to you NDC Oslo 2026 fi Marcus Bointon — Magical client-side logging
  4. “You can't x what you don't know is broken.” –Me

    fi Marcus Bointon — Magical client-side logging NDC Oslo 2026
  5. CONTENT SECURITY POLICY • Primary purpose: block XSS, limit resource

    origins • W3C CSP level 2 2016 • report-uri directive (takes a full URL) • W3C CSP level 3 2025 • Support for Reporting API Marcus Bointon — Magical client-side logging NDC Oslo 2026
  6. CSP FLOW Request site Server Browser Return page & CSP

    Yes Fetch resource Request resource CSP allows? No Report violation
  7. CONTENT SECURITY POLICY HEADER Content-Security-Policy: default-src 'none'; script-src 'self'; img-src

    'self'; report-uri https: example.com/csp; report-to csp; / NDC Oslo 2026 / Marcus Bointon — Magical client-side logging
  8. CSP VERSION JUGGLING D R d e A t CSP

    level 2 F a T c CSP level 3 report-to e report-uri r p e D Implement both, browser will choose Marcus Bointon — Magical client-side logging NDC Oslo 2026
  9. NAMING CONFUSION • report-uri CSP2 directive is deprecated, report-to is

    new in CSP3 • Report-To HTTP header is deprecated, Reporting-Endpoints is new in RAPIv1 m e s e h t t e g o t y s p u d e ix Ea Marcus Bointon — Magical client-side logging NDC Oslo 2026
  10. WHAT'S IN THE REPORTING API? • https://w3c.github.io/reporting/ • Report-To &

    Reporting-Endpoints headers • JavaScript API in browsers • Speci cation for other headers to use it • Mechanism for sending reports • Top-level format for reports fi Marcus Bointon — Magical client-side logging NDC Oslo 2026
  11. REPORTING API REPORT-TO HEADER • Reporting API spec "v0" —

    Obsolete Report-To: { "group": "csp", "max_age": 31536000, "endpoints": [ { "url": "https: example.com/csp" }, { "url": "https: backup.com/reports" } ] } / / / NDC Oslo 2026 / Marcus Bointon — Magical client-side logging
  12. REPORTING-ENDPOINTS HEADER • Reporting API spec "v1" Reporting-Endpoints: csp="https: example.com/csp",

    nel="https: example.com/nel" • Must use HTTPS, can be relative / / / / Marcus Bointon — Magical client-side logging NDC Oslo 2026
  13. REPORTING API SUPPORT • All good in 2026! Marcus Bointon

    — Magical client-side logging NDC Oslo 2026
  14. WHAT'S IN A CSP2 REPORT? { "csp-report": { "document-uri": "http:

    example.org/page.html", "referrer": "http: evil.example.com/haxor.html", "blocked-uri": "http: evil.example.com/image.png", "violated-directive": "default-src 'self'", "effective-directive": "img-src", "original-policy": "default-src 'self'; report-uri http: example.org/csp-report" } } / / / NDC Oslo 2026 / / / / / Marcus Bointon — Magical client-side logging
  15. WHAT'S IN A CSP3 REPORT? { "age": 0, "type": "csp-violation",

    "url": "http: example.org/page.html", "user_agent": "Mozilla/5.0", "body": { "documentURL": "http: example.org/page.html", "referrer": "http: evil.example.com/haxor.html", "blockedURL": "http: evil.example.com/image.png", "violatedDirective": "default-src 'self'", "effectiveDirective": "img-src", "originalPolicy": "default-src 'self'; report-to csp", "disposition": "enforce", "statusCode": 200 / / / / / / / / Marcus Bointon — Magical client-side logging NDC Oslo 2026
  16. WHAT CAN GENERATE REPORTS? • CSP • Connection-Allowlist • CSP

    hashes • Intervention • Permissions-Policy • Cross-Origin Opener • NEL • Deprecation Policy • Document-Policy • Browser crashes Marcus Bointon — Magical client-side logging NDC Oslo 2026
  17. CSP3 HASH REPORTING • SBOMs are popular • Dif cult

    to make on very dynamic sites • CSP3 can report the hash of every loaded script • Add 'report-sha256' to script-src in your CSP • External domains need crossorigin="anonymous" • Not the same as integrity hashes (SRI) fi Marcus Bointon — Magical client-side logging NDC Oslo 2026
  18. WHAT'S IN A CSP3 HASH REPORT? { } "type": "csp-hash",

    "age": 12, "url": "https: example.com/", "user_agent": "Mozilla/5.0", "body": { "document_url": "https: example.com/", "subresource_url": "https: example.com/main.js", "hash": "sha256-2bFFc6BUJ67aVaBG/pflFLuNP5C4bHtJjlUJzaQVZhs=", "type": "subresource", "destination": "script" } / / / NDC Oslo 2026 / / / Marcus Bointon — Magical client-side logging
  19. PERMISSIONS POLICY VIOLATIONS • Permissions-Policy header lets the server control

    client features • Early versions were called Feature-Policy, now defunct • microphone=(), geolocation=() • Supports reporting on each feature separately: • microphone=();report-to=pp, to=pp geolocation=();report- • Sends reports when a script tries to use a feature that is not allowed Marcus Bointon — Magical client-side logging NDC Oslo 2026
  20. WHAT'S IN A PPV REPORT? { "type": "permissions-policy-violation", "url": "https:

    example.com/", "user_agent": "Mozilla/5.0", "age": 120, "body": { "sourceFile": "https: example.com/permissions.js", "columnNumber": 23, "disposition": "enforce", "lineNumber": 1, "message": "Permissions policy violation: Geolocation access has been blocked because of a permissions policy applied to the current document. See https: crbug.com/414348233 for more details.", "policyId": "geolocation" } } / / / / / / Marcus Bointon — Magical client-side logging NDC Oslo 2026
  21. NETWORK ERROR LOGGING (NEL) • DNS • Lookup failures, unreachable

    server • Connection • TCP & TLS failures, e.g. timeouts, certi cates • Application • HTTP, redirect loops, user abort, unknown NDC Oslo 2026 fi Marcus Bointon — Magical client-side logging
  22. NEL HEADER • NEL: {"report_to": "nel", "max_age": 31536000, "failure_fraction": 1.0}

    • report-to URL de ned in Report-To header NOT Reporting-Endpoints! NDC Oslo 2026 fi Marcus Bointon — Magical client-side logging
  23. WHAT'S IN AN NEL REPORT? { "age": 147, "type": "network-error",

    "url": "https: example.org/page.html", "user_agent": "Mozilla/5.0", "body": { "sampling_fraction": 1.0, "server_ip": "192.168.0.123", "protocol": "http/1.1", "method": "GET", "request_headers": {}, "response_headers": {}, "status_code": 0, "elapsed_time": 5000, "phase": "dns", "type": "dns.name_not_resolved", "url": "https: evil.example.com/image.png" / / / / Marcus Bointon — Magical client-side logging NDC Oslo 2026
  24. NEL ISN'T VERY USEFUL • Reports are sent to the

    target domain • e.g. your domain fails to load a script from example.com • reports to example.com, not your domain • Client must have seen target domain's NEL beforehand • Can report problems on your own domain • But you’ll already know about them from server side • May be good for CDN owners 🤷 Marcus Bointon — Magical client-side logging NDC Oslo 2026
  25. NETWORK EFFICIENCY GUARDRAILS • Part of Document-Policy • Microsoft draft

    only (Edge 146+) • Text content served without compression • Images bigger than 200k • data: URLs bigger than 100k • Document-Policy: force-load-at-top, network-efficiency-guardrails;report-to=doc Marcus Bointon — Magical client-side logging NDC Oslo 2026
  26. CONNECTION-ALLOWLIST • Explicit endpoints browser may talk to • Connection-Allowlist:

    "https: trusted.com (response-origin "); report-to=ca • Applied at a low level to all request types • Aimed at sandboxing AI agents and canvas scripts * NDC Oslo 2026 / / / Marcus Bointon — Magical client-side logging
  27. DEFAULT REPORTING ENDPOINT • Some reporting channels don't have anywhere

    to put a report-to directive • e.g. JavaScript deprecation, intervention, browser crash • Create an endpoint called default in Report-To & Reporting-Endpoints Marcus Bointon — Magical client-side logging NDC Oslo 2026
  28. RECEIVING REPORTS • Set target URLs through directives and headers

    • Up to you to parse, log, summarise, monitor, and understand • Can handle in your own app or defer to external services • report-uri.com (Sponsor) • centralcsp.com • reporting-api.app Marcus Bointon — Magical client-side logging NDC Oslo 2026
  29. HANDLING REPORTS • Browsers POST to target endpoints • in

    application/reports+json format • Sent out-of-band, after a delay up to 1 minute, may be batched • Browser sends a CORS pre- ight OPTIONS request rst • 3rd-party services for aggregation, analysis, and reporting • My Laravel library: synchro/laravel-violations fi NDC Oslo 2026 fl Marcus Bointon — Magical client-side logging
  30. PRIVACY IMPACT • If you report to a 3P service,

    client traf exposed to them c is • Reported as a leak by webbkoll.5july.net • Proxy the service through your app • laravel-violations can do this for you NDC Oslo 2026 fi Marcus Bointon — Magical client-side logging
  31. SUMMARY • Set both Report-To and Reporting- Endpoints headers •

    Set endpoints in report-uri and report-to • Set NEL to point at a Report-To endpoint • Receive reports and collate them • Finally see what your clients are seeing! Marcus Bointon — Magical client-side logging NDC Oslo 2026
  32. REFERENCES • CSP2: https://www.w3.org/TR/CSP2/ • CSP3: https://www.w3.org/TR/CSP3/ • NEL: https://www.w3.org/TR/network-error-logging/

    • Reporting API https://w3c.github.io/reporting • Connection-Allowlist https://wicg.github.io/connection-allowlists • CSP evaluator: https://csp-evaluator.withgoogle.com • Report-URI: https://report-uri.com Marcus Bointon — Magical client-side logging NDC Oslo 2026
  33. THANK YOU! @[email protected] GitHub: Synchro Feedback Sponsor me! Blog https://marcus.bointon.com

    Buy my music! Marcus Bointon — Magical client-side logging NDC Oslo 2026