daybook/issues/018-handover-to-llm-test-round-3.md
peter 54f8e8ea3b Add round-3 handover doc for the LLM test project
Covers the #014-#016 fixes (sanitization+CSP, nested-JSON 400, ragged-CSV
normalization) and flags the sanitizer as the top round-4 adversarial
target (mutation XSS, attribute/scheme bypasses, CSP presence). Notes #017
is a design issue, not a bug to re-report, and the aesthetic/UI changes
have no API surface.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 13:47:46 +01:00

4.6 KiB
Raw Permalink Blame History

018 — Handover to AGENT_DAYBOOK__LLM_TEST (round 3)

Status: For information — a handback covering everything fixed/changed since the round-2 handoff (#013).

Round-2 testing (against #013's suggestions) filed #014, #015, #016 — all now fixed. This round-3 handoff summarizes those fixes and points at where the fresh adversarial surface is, plus one new design issue (#017) that is not a bug and shouldn't be re-reported.

All changes are on main (pushed to Forgejo) and live on the local dev instance (http://127.0.0.1:8001) via autoreload — no restart needed. Test as always with the test / testpwd account and clean up after yourself.

Fixes since #013 (issues you filed)

  • #014 (High) — stored XSS. markdown, html_fragment, and deck are now allowlist-sanitized (nh3) at create time: <script>, on* handlers, <style>, and javascript:/data: URLs are stripped, while formatting/ tables/links/images (incl. relative /assets/<id>) survive. Those kinds are also served with Content-Security-Policy: script-src 'none' (on both /a/{id} and the public /s/{token} route). html_full is deliberately not sanitized (verbatim escape hatch) and json/csv keep their existing escape_script_body defense.
  • #015 (Med) — deeply nested JSON → 500. Now returns 400 on both paths: the json-kind validator catches RecursionError, and a new DRF EXCEPTION_HANDLER maps parser-level RecursionError (deep nesting anywhere in the request body) to 400.
  • #016 (Low-Med) — ragged CSV rows. wrap_csv_viewer now normalizes every row to the max width (long rows widen the columns with auto-named Column N; short rows pad with ""), so no cell is dropped.

Other changes (context, mostly not API-surface)

  • Document artifact backgrounds unified to one off-white (#faf9f6) across markdown/html_fragment/json/csv (report/tasks/base themes). Deck stays dark; html_full/pdf unchanged. Only relevant to you as: the rendered HTML background value changed — no behavioral/API change.
  • UI-only work (dark mode toggle, top-bar logo, sidebar width behavior, greyscale chrome). No API surface.
  • #017 filed — customizable theme variants. A design issue (feature request), not a bug. Don't re-report theme/color inflexibility as a bug; it's tracked.

Suggested Round-4 Probes

Prioritized by where the new surface is riskiest.

The sanitizer (#014) — now the top adversarial target

The XSS fix is an allowlist sanitizer; the classic follow-up is trying to get past it. Worth hard probing on markdown, html_fragment, deck:

  • Mutation/parser-confusion XSS: malformed nesting, stray </>, comments (<!-- -->), CDATA, <svg>/<math> foreign-content vectors, <noscript>/<template>, deprecated/odd tags — anything that might re-parse into script after nh3 serializes.
  • Attribute vectors: on* variants, style= (should be stripped), href/src with javascript:, data:, vbscript:, whitespace/newline/ encoding tricks (java\tscript:, &#106;avascript:), srcset, formaction.
  • Allowlisted-tag abuse: does anything survive on the permitted tags (a/img/etc.) that shouldn't — e.g. <a href> protocol bypasses, <img src> with odd schemes?
  • CSP presence: confirm script-src 'none' is actually on the response for markdown/deck/html_fragment (both /a/ and /s/), and absent for html_full and json/csv. Confirm markdown/deck/html_fragment pages contain no executable inline script at all after sanitization.
  • html_full is out of scope — it's verbatim by design; a <script> surviving there is not a bug (documented). Don't file it.
  • Verify the sanitizer didn't over-strip: tables, code highlighting, links, relative /assets images, headings/lists still render.

#015 recursion — other sites

  • Deeply nested metadata / tag_colors (string-parsed JSON), deeply nested arrays vs objects, right-at-the-limit depths. Confirm 400 not 500.

#016 CSV — other raggedness

  • Header shorter than data rows, entirely empty first row, mixed quoting with ragged widths, a row that's all empty cells. Confirm no data lost and the auto-named columns behave.

Regression sweep

  • Re-run the #002–#012 repros briefly to confirm none regressed (esp. the #010 quota race and #006 eviction, which have thin/no automated coverage).

As always: use test/testpwd, clean up, check artifacts/views.py before calling a surprise a bug (some behavior is documented/by-design), and file anything real as a new numbered issue (next is #019), linking back if it's a variant of a closed one.