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>
93 lines
4.6 KiB
Markdown
93 lines
4.6 KiB
Markdown
# 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:`, `javascript:`), `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.
|