fix(security): keep channel-metadata and install-policy truncation surrogate-safe#102266
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 9, 2026, 1:28 AM ET / 05:28 UTC. Summary PR surface: Source +2, Tests +65. Total +67 across 4 files. Reproducibility: yes. Source inspection shows current main can split a surrogate pair at the channel metadata 397-code-unit cut and the install-policy 1000-code-unit cut. Review metrics: none identified. Stored data model Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Next step before merge
Security Review detailsBest possible solution: Land the helper swap with the exact boundary tests after normal maintainer review and current-head merge/check gating. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection shows current main can split a surrogate pair at the channel metadata 397-code-unit cut and the install-policy 1000-code-unit cut. Is this the best way to solve the issue? Yes. Reusing the existing AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against acac359de64e. Label changesLabel justifications:
Evidence reviewedPR surface: Source +2, Tests +65. Total +67 across 4 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (3 earlier review cycles)
|
…rrogate-safe channel-metadata.ts and install-policy.ts both had private truncateText functions using String.prototype.slice(0, N) on user-visible text. channel-metadata is explicitly user-controlled untrusted content that gets injected into LLM prompt context -- a dangling surrogate from unsafe truncation would corrupt the prompt with invalid Unicode, affecting token counting and potentially LLM response quality. Replace .slice(0, ...) with truncateUtf16Safe(...) in both files so the truncation point always falls on a complete code-point boundary. Add test coverage for buildUntrustedChannelMetadata with emoji at both the entry-level (400-char) and outer (800-char) truncation boundaries.
be886b2 to
6a94d23
Compare
|
Land-ready proof for exact head
The reviewed implementation is the best bounded fix: it retains the existing limits, external-content wrapping, policy decisions, and fail-closed behavior while replacing only the unsafe prefix cuts. |
|
Merged via squash.
|
…rrogate-safe (openclaw#102266) * fix(security): keep channel-metadata and install-policy truncation surrogate-safe channel-metadata.ts and install-policy.ts both had private truncateText functions using String.prototype.slice(0, N) on user-visible text. channel-metadata is explicitly user-controlled untrusted content that gets injected into LLM prompt context -- a dangling surrogate from unsafe truncation would corrupt the prompt with invalid Unicode, affecting token counting and potentially LLM response quality. Replace .slice(0, ...) with truncateUtf16Safe(...) in both files so the truncation point always falls on a complete code-point boundary. Add test coverage for buildUntrustedChannelMetadata with emoji at both the entry-level (400-char) and outer (800-char) truncation boundaries. * test(security): prove UTF-16 truncation boundaries --------- Co-authored-by: Peter Steinberger <[email protected]>
What Problem This Solves
Security-owned text limits in channel metadata and install-policy results use raw UTF-16 code-unit slices. When a limit stops after the high surrogate of an astral character, OpenClaw introduces malformed text into wrapped prompt metadata, policy block reasons, or normalized findings.
Why This Change Was Made
The two private truncation helpers now use the existing
truncateUtf16Safeimplementation from@openclaw/normalization-core/utf16-slicewhile preserving their current limits and suffix behavior.No config, schema, protocol, dependency, or security decision changes.
User Impact
Long untrusted channel descriptions and long install-policy output no longer end in a surrogate half introduced by OpenClaw. Short text and text not crossing an astral-character boundary remain unchanged.
Evidence
runInstallPolicyassertion for a block reason whose emoji crosses the 1,000-unit boundary.git diff --check: passed.The submitted generic lone-surrogate test was moved from
test/security/to the owningsrc/security/shard and replaced with exact behavioral expectations. The previously untested install-policy change now has production-path coverage.