fix: reject control characters in write tool content params - #361
Conversation
Defense-in-depth against invisible unmatchable bytes on disk — a NUL written via JSON \uXXXX decoding silently breaks exact-match old_text edits because the byte doesn't survive a round-trip through the MCP transport. Guarding at the write boundary (writeNote, patchNote, replaceInNote, updateMemory) prevents the stuck-byte scenario entirely. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Sorry @aliasunder, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
PR Code Suggestions ✨Explore these optional code suggestions:
|
…re tree Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…trol-char guard Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…o-bar fix - All control-character rejection tests now assert the full deterministic error message instead of a substring (toThrow partial match) - Added bare CR (U+000D) allow test — the regex specifically excludes CR but only CRLF was tested, not standalone CR - "reports first occurrence only" now verifies the second control char (U+0002) is absent from the error, closing a two-bar gap where the test could pass even if both occurrences were reported Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Same advisory already suppressed in osv-scanner.toml (PR #360) — Trivy needs its own .trivyignore. Windows-only serve-static path traversal, not applicable (Linux Docker, no serve-static). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@CodeRabbit review |
✅ Action performedReview finished.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (12)
📝 WalkthroughWalkthroughChangesControl-character validation
Trivy suppression
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Exact-match toThrow on the full message already proves the second code point is absent — the helper added indirection without value. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
assertNoControlCharactersguard utility that rejects C0 controls (except tab/LF/CR), DEL, and C1 controls in content written to vault noteswriteNote(body),patchNote(content),replaceInNote(newText),updateMemory(entry + section)Errors:sectionMotivation: A NUL byte written via JSON
\uXXXXescape decoding was faithfully persisted to disk, where it silently broke exact-matchold_textedits — invisible invault_read_noteoutput, unmatchable in tool params. Defense-in-depth: a control byte in a markdown note is never intended, and rejecting it with a clear error beats a stuck unmatchable byte on disk.Test plan
npm test -- --run src/utils/__tests__/assert-no-control-characters.test.ts— 14 unit testsnpm test -- --run src/vault-mcp/vault-operations/__tests__/vault-filesystem.test.ts— writeNote rejectionnpm test -- --run src/vault-mcp/vault-operations/__tests__/vault-patcher.test.ts— patchNote + replaceInNote rejectionnpm test -- --run src/vault-mcp/vault-operations/__tests__/memory-store.test.ts— updateMemory entry + section rejectionnpm run lint— 0 errors🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Documentation
Tests