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>
This commit is contained in:
peter 2026-09-03 13:47:46 +01:00
parent 31999dcac2
commit 54f8e8ea3b

View file

@ -0,0 +1,93 @@
# 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.