Skip to content

The rest of the public-surface review (area 1b) - #306

Merged
adamjohnwright merged 1 commit into
mainfrom
review-1b-rest
Oct 3, 2026
Merged

adamjohnwright merged 1 commit into
mainfrom
review-1b-rest

Conversation

@adamjohnwright

Copy link
Copy Markdown
Contributor

This finishes the findings from the max-level review of the public surface. The websocket gate and the captcha cookie went in #305.

Finding Fix Checked by
Handed-off summaries are written by the model, and the chat renders HTML. Markup a visitor steered into an answer ran in the browser of whoever opened their link. inert_html(): every < in a summary is escaped, and markdown is kept Unit test: an iframe+script summary has no unescaped < and keeps its bold
The handoff seed could still race a message. Chainlit's startup task_end unlocks the message box in the middle of seeding. Messages wait for their session's in-progress seed, up to 45s Browser: the analysis handoff follow-up passed 5/5
The disclaimer had not been shown since Chainlit 2.11 (the footer is now a div) custom.js matches .watermark Browser: the disclaimer is visible
With edit_message on, an edit left the edited-out text in the model's history edit_message = false —
OAuth secrets that arrive as Docker secrets were never seen, because they loaded after chainlit was imported Secrets load before any chainlit import Source-order test
Clock skew made the website's fresh tokens fail; a bad verifying key failed only at request time 30s leeway on iat/nbf (expiry stays strict). The key must parse as an Ed25519 or RSA public key. Unit tests: skew allowed, far future refused, private key and garbage refused at load
Session ids appeared in the access log, and a guest's session id is enough to take over its session RedactSessionIds filter on uvicorn.access Unit test
An empty CHAINLIT_URI sent the captcha page into a redirect loop; a missing site key rendered None Empty is treated as unset; a missing site key stops startup —
reclaim-docker-space.sh --all removed named volumes, and unknown arguments pruned before warning Only anonymous volumes are removed; unknown arguments exit before anything runs Stub docker on PATH
The beta docs still described the unset-key bypass and pinned an image that has it Template and README corrected —

Browser checks

Both run against a local instance of this branch.

  • HTTPS with Turnstile's test keys: the captcha passes, the v2. cookie is set, an answer arrives over the websocket, and the handoff survives the captcha.
  • Plain HTTP: the disclaimer shows, and the analysis handoff passes end to end, including the follow-up 5 times in 5.

The follow-up check had earlier failed 3 of 5 times. That turned out to be the test harness: the restored disclaimer gave it enough stable text to declare an answer finished before the model had replied. The scripts in ~/chat-uitest now ignore the footer.

Still open: one decision for Adam

unsafe_allow_html = true is the root cause behind both HTML findings. It is needed today because answers cite with <a href> anchors. Turning it off means changing answers to cite with markdown links, which touches the answer path the search page shares.

🤖 Generated with Claude Code

- Handed-off summaries are model-written and the chat renders HTML, so
  markup a visitor steered into an answer ran in the browser of whoever
  opened their link. Summaries now have every '<' made inert (markdown
  kept); the question was escaped in #301.
- Messages wait for an in-progress handoff seed. Running the claim as a
  task did not hold them: Chainlit's own startup task_end unlocks the box
  mid-seed whenever the claim arrives first.
- The disclaimer had not been shown since Chainlit 2.11, whose footer is a
  div, not an anchor. custom.js now matches it (checked in a browser).
- edit_message is off: an edit removed later turns from the screen but not
  from the model's history, so edited-out text kept being sent.
- Secrets are loaded before chainlit is imported; chainlit reads OAuth
  client secrets once at import, so a Docker-secret one was never seen.
- Caller tokens: 30s leeway for issue and not-before times (expiry stays
  strict); a verifying key that is not a PEM public key stops startup.
- Session ids are redacted from the access log; for a guest the id is the
  whole credential.
- An empty CHAINLIT_URI is treated as unset (it looped the captcha page);
  a missing site key stops startup (it rendered data-sitekey=None).
- reclaim-docker-space.sh: --all removes only anonymous volumes, as its
  header always said; unknown arguments exit before anything runs.
- The beta template and README no longer describe the unset-key bypass
  or pin an image that has it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@adamjohnwright
adamjohnwright merged commit ce792d9 into main Oct 3, 2026
10 checks passed
@adamjohnwright
adamjohnwright deleted the review-1b-rest branch October 3, 2026 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant