Skip to content

fix(core): sanitize peer-controlled names in cleanRemote (#75) - #76

Merged
Birfy merged 3 commits into
ThinkFlowLab:mainfrom
Birfy:cursor/sanitize-cleanremote-names-cc89
Oct 15, 2026
Merged

Birfy merged 3 commits into
ThinkFlowLab:mainfrom
Birfy:cursor/sanitize-cleanremote-names-cc89

Conversation

@Birfy

@Birfy Birfy commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator

Closes #75.

cleanRemote now strips @ and control characters/newlines from a friend Bot's published name, homeName and owner, then applies the existing 60-char cap. Empty results fall back to the handle (without @) or a remote Bot. The handle field is unchanged.

Model-visible paths traced: delivery fromName uses the sanitized name and still goes through cleanName plus the untrusted fence; list_bots friend lines come from the same record; group room logs use local team names.

Change lives in patch 0002-flybot-api-host (core/ + regenerated patch); ds-bot/ untouched.

Tests: negative cases for a name containing another member's handle, newlines/control chars, and the same for homeName and owner. core: 621 pass; social: 34 pass; patches check, build-client check, lint/arch-docs pass.

cleanRemote only length-capped published name, homeName and owner, so a
peer could put another member's @handle or a newline into the display
name the client now shows verbatim. Strip @ and control
characters/newlines at the record boundary and keep the 60-character
cap. Delivery fromName still goes through cleanName and the untrusted
fence; list_bots friends lines take the sanitized record.

Fixes ThinkFlowLab#75

Co-authored-by: Danyang Chen <birfychen@gmail.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T08:58:12.186340Z a763683 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a763683b40

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread core/src/host/hooks.js
const cleanRemote = (plugin, bot) => {
const remote = toRemote(bot.handle)
return { handle: remote.handle, home: bot.home ? toRemote(bot.home).handle : remote.home, name: String(bot.name ?? remote.handle).slice(0, 60), ...(bot.homeName ? { homeName: String(bot.homeName).slice(0, 60) } : {}), ...(bot.owner ? { owner: String(bot.owner).slice(0, 60) } : {}), plugin, remote: true }
const name = cleanPublishedName(bot.name) || cleanPublishedName(remote.handle) || 'a remote Bot'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Sanitize names passed directly by remote senders

When Bot Social processes a normal message.received, plugins/social/src/social.js:495-496 supplies from.name from the peer's display_name, and its cleanText does not strip @. send() at line 427 prefers that value over remoteMembers.get(...).name, while delivery.cleanName also preserves @, so this roster-only sanitization is bypassed and a peer named Eve @coder.bob.home still appears in the model-visible trusted [Message from ...] header. Apply the sanitizer at the remote send boundary and cover the actual Bot Social poll payload.

AGENTS.md reference: AGENTS.md:L18-L18

Useful? React with 👍 / 👎.

Comment thread core/src/host/hooks.js
const name = cleanPublishedName(bot.name) || cleanPublishedName(remote.handle) || 'a remote Bot'
const homeName = cleanPublishedName(bot.homeName)
const owner = cleanPublishedName(bot.owner)
return { handle: remote.handle, home: bot.home ? toRemote(bot.home).handle : remote.home, name, ...(homeName ? { homeName } : {}), ...(owner ? { owner } : {}), plugin, remote: true }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Normalize labels already persisted in state

For a profile upgraded from the previous version, state.flybot.remote and the corresponding remote-chat Bot can already contain an @-bearing peer name. This sanitizer only runs on the next remote.publish; remoteMembers.list() and list_bots read the saved records verbatim, and Bot Social's startup refresh is fire-and-forget with failures swallowed, so an unavailable/removed plugin leaves the spoofed label active indefinitely. Normalize or migrate both persisted roster and chat records on load/read rather than relying on a successful future publish.

AGENTS.md reference: AGENTS.md:L18-L18

Useful? React with 👍 / 👎.

Comment thread core/src/host/hooks.js
const same = (a, b) => JSON.stringify(a) === JSON.stringify(b)
// Peer-controlled labels (display name, home, owner): strip @ so they cannot look
// like a mention of another Bot, strip controls/newlines, keep a 60-char cap (#75).
export const cleanPublishedName = (value) => String(value ?? '').replace(/@/g, '').replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 60)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Strip bidi formatting controls from published names

For peer labels containing bidi controls such as U+202E or U+2066, this regex removes only C0/C1 controls and the two Unicode line separators; \s+ does not remove these Cf characters. They therefore survive in the stored name and can reorder or hide the label and its adjacent handle in trusted headers and UI sender rows, defeating the anti-impersonation boundary despite the documented claim that controls are stripped. Remove Unicode bidi/format controls and add a negative test for them.

AGENTS.md reference: AGENTS.md:L18-L18

Useful? React with 👍 / 👎.

@Birfy
Birfy enabled auto-merge October 15, 2026 10:04
@Birfy
Birfy merged commit c1a4ca4 into ThinkFlowLab:main Oct 15, 2026
5 checks 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.

cleanRemote: sanitize peer-controlled names (strip @ and control chars), not just length-cap

2 participants