Skip to content

[codex] Batch E: XSS, comms & realtime hardening (round-2 audit) - #23

Merged
alextitov19 merged 1 commit into
mainfrom
codex/fix-xss-comms-realtime
Jun 19, 2026
Merged

[codex] Batch E: XSS, comms & realtime hardening (round-2 audit)#23
alextitov19 merged 1 commit into
mainfrom
codex/fix-xss-comms-realtime

Conversation

@alextitov19

Copy link
Copy Markdown
Contributor

Fixes the round-2 XSS/comms/realtime findings (discussion #13).

  • Add SDK store and query primitives #4 (HIGH) feedback admin detail modal: every visitor-supplied field (body, page_url, element_selector, screenshot src, visitor name/email, per-comment fields) is now escH()-escaped before innerHTML (matching the list/card renderers). Closes stored XSS → admin session takeover.
  • Med email From is CRLF-stripped like the other header fields.
  • Med XLSX cells run through csvSafeCell (formula-injection) before xmlEscape.
  • Med WebSocket write-locked admission re-checks all three caps (global + per-user + per-anon-IP), not just global.
  • Med presence storage keys namespaced by tenant group (cross-tenant presence enumeration closed; no schema change).
  • Low SMS recipient normalized + validated to E.164 before rate-limit (variants share a bucket; bad numbers rejected pre-billing).

Not changed: isPrivateURL alt-IP encodings are already fail-closed + Go handles IPv4-mapped IPv6; PDF --no-sandbox is env-dependent and its echo is dev-only.

Tests added; go build+vet+test -tags sqlite_fts5 ./... green; -race clean.

- #4 (HIGH) feedback admin detail modal: every visitor-supplied field
  (body, page_url, element_selector, screenshot src, visitor name/email, and
  per-comment user_email/body/created_at) is now escH()-escaped before
  innerHTML, matching the list/card renderers. Closes stored XSS -> admin
  session takeover.
- Med email: opts.From is CRLF-stripped like the other header fields (a
  'send as'/reply-routing caller can't inject Bcc/extra headers).
- Med XLSX: data cells run through csvSafeCell (formula-injection neutralization)
  before xmlEscape, matching the CSV export path.
- Med WebSocket: the write-locked admission re-check now recomputes ALL THREE
  caps (global + per-user + per-anon-IP), not just the global ceiling, so a
  burst of handshakes from one user/IP can't exceed its per-class cap.
- Med presence: storage keys are namespaced by the caller's tenant group
  (presenceKey) so a user in one group can't read/write another group's slug
  via GET/heartbeat - cross-tenant presence enumeration closed. No schema change.
- Low SMS: recipient normalized + validated to E.164 before the rate-limit
  check, so format variants share one bucket and bad/premium-length numbers are
  rejected before billing the provider.

Not changed: isPrivateURL alt-IP encodings are already fail-closed (LookupIP
fails on non-dotted hosts) and Go handles IPv4-mapped IPv6; PDF --no-sandbox is
environment-dependent and its error echo is dev-only.

go build + vet + test -tags sqlite_fts5 ./... green; -race clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alextitov19
alextitov19 merged commit 6bc3156 into main Jun 19, 2026
1 check passed
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