Skip to content

Harden presence titles using server-owned metadata#11

Open
LynnColeArt wants to merge 1 commit into
BaderBC:masterfrom
LynnColeArt:fix/presence-title-trust
Open

Harden presence titles using server-owned metadata#11
LynnColeArt wants to merge 1 commit into
BaderBC:masterfrom
LynnColeArt:fix/presence-title-trust

Conversation

@LynnColeArt
Copy link
Copy Markdown

@LynnColeArt LynnColeArt commented May 14, 2026

Why

Implemented a security-focused presence hardening patch so the live "Currently Being Consulted" panel can’t be driven by untrusted title text from users.

What changed

  • Removed client-provided ti/title fields from presence websocket messages.
  • Canonicalized incoming slugs with slugify before storing per-socket location.
  • Switched presence titles to server-owned article metadata (KV title) with slug fallback.
  • Kept behavior for title updates deterministic and resistant to malformed/stale client transitions.

Why this was necessary

I observed that a user could navigate with crafted input and affect the sidebar text, making the panel a likely vector for content poisoning. The previous approach trusted client-provided title values, so hostile names could appear in live UI panels that are otherwise read as authoritative app state.

Note

This patch focused on presence-title trust boundaries. I intentionally left broader input/output hardening (e.g., full comment/comment-thread XSS review) for follow-up, since that should likely be handled in a separate PR.

Summary by CodeRabbit

  • Refactor
    • Optimized title and presence tracking infrastructure by moving title resolution to the server, improving data consistency and reducing client-side state management complexity.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 25e95044-e0bf-4dc0-86da-546a1ec0c86b

📥 Commits

Reviewing files that changed from the base of the PR and between 46759b0 and 2d721c7.

📒 Files selected for processing (4)
  • src/client/App.tsx
  • src/client/usePresence.ts
  • src/worker/index.ts
  • src/worker/presence.ts

📝 Walkthrough

Walkthrough

Client stops sending article titles in presence messages. The server now derives and caches titles from metadata using canonicalized slugs and a KV namespace. usePresence hook signature simplified to accept only slug. WebSocket protocol updated to remove ti field from client registration.

Changes

Title Resolution Shift

Layer / File(s) Summary
Client-side title state and messaging cleanup
src/client/App.tsx
App component removes articleTitle state previously used to coordinate page-title extraction with presence broadcast. usePresence hook now called with slug only, and title extraction from streamed HTML <h1> only updates document.title locally without feeding into state. Slug transitions and popstate handler no longer include title-clearing logic.
usePresence hook and protocol update
src/client/usePresence.ts
usePresence exported signature now accepts only `slug: string
Server-side title derivation and KV integration
src/worker/presence.ts
Server imports slugToTitle and slugify utilities, adds ARTICLES: KVNamespace to PresenceEnv, and canonicalizes incoming slugs. Title bookkeeping refactored to asynchronously resolve titles from KV metadata via new resolveTitle helper (falling back to slugToTitle deterministically). Broadcast triggered on both slug and title-cache changes. Top-N snapshot generation populates ti from DO-level titles cache with fallback.
Protocol documentation update
src/worker/index.ts
Comment describing /api/presence WebSocket client navigation message updated to reflect {t:"r", s} format without ti field.

Sequence Diagram

sequenceDiagram
  participant Client
  participant PresenceDO
  participant ARTICLES_KV
  Client->>PresenceDO: {t:"r", s: slug}
  PresenceDO->>PresenceDO: canonicalize slug via slugify
  PresenceDO->>ARTICLES_KV: resolveTitle(slug)
  ARTICLES_KV-->>PresenceDO: {title?: string}
  PresenceDO->>PresenceDO: cache title in DO titles map
  PresenceDO->>PresenceDO: broadcast presence with ti from cache
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related issues

Poem

🐰 No title in the breeze,
Server speaks with certainty—
Slugs bloom true at last.
The rabbit hops to cached delight, 📚

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Harden presence titles using server-owned metadata' clearly and specifically describes the main security-focused change: removing client-provided titles and using server-owned metadata instead.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

@LynnColeArt
Copy link
Copy Markdown
Author

Thanks for taking this; I filed a follow-up issue to keep broader XSS hardening explicit: #12

@LynnColeArt LynnColeArt marked this pull request as ready for review May 14, 2026 04:44
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