Skip to content

Commit b714fdb

Browse files
fix(sandbox): keep redacted session keys UTF-16 safe (#102969)
* fix(sandbox): keep redacted session keys UTF-16 safe * test(sandbox): cover UTF-16 redaction boundaries --------- Co-authored-by: Peter Steinberger <[email protected]>
1 parent 08a957e commit b714fdb

2 files changed

Lines changed: 53 additions & 1 deletion

File tree

src/agents/sandbox/runtime-status.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Resolves whether a session is sandboxed and explains policy blocks before tool execution.
55
*/
66
import { normalizeOptionalLowercaseString } from "@openclaw/normalization-core/string-coerce";
7+
import { sliceUtf16Safe, truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice";
78
import { formatCliCommand } from "../../cli/command-format.js";
89
import {
910
canonicalizeMainSessionAlias,
@@ -110,7 +111,7 @@ function redactSessionKey(value: string): string {
110111
if (trimmed.length <= 12) {
111112
return "(redacted)";
112113
}
113-
return `${sanitizeForSingleLineDisplay(trimmed.slice(0, 6))}${sanitizeForSingleLineDisplay(trimmed.slice(-6))}`;
114+
return `${sanitizeForSingleLineDisplay(truncateUtf16Safe(trimmed, 6))}${sanitizeForSingleLineDisplay(sliceUtf16Safe(trimmed, -6))}`;
114115
}
115116

116117
function shellEscapeSingleArg(value: string): string {

src/agents/sandbox/tool-policy.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,57 @@ describe("sandbox/tool-policy", () => {
305305
);
306306
});
307307

308+
it.each([
309+
{
310+
boundary: "prefix",
311+
sessionKey: `abcde\u{1f600}middle123456`,
312+
expectedLabel: "abcde…123456",
313+
},
314+
{
315+
boundary: "suffix",
316+
sessionKey: `abcdefmiddle\u{1f600}12345`,
317+
expectedLabel: "abcdef…12345",
318+
},
319+
{
320+
boundary: "both",
321+
sessionKey: `abcde\u{1f600}middle\u{1f600}12345`,
322+
expectedLabel: "abcde…12345",
323+
},
324+
])("keeps redacted session keys UTF-16 safe at the $boundary boundary", ({
325+
sessionKey,
326+
expectedLabel,
327+
}) => {
328+
const cfg: OpenClawConfig = {
329+
agents: {
330+
defaults: {
331+
sandbox: { mode: "all", scope: "agent" },
332+
},
333+
},
334+
tools: {
335+
sandbox: {
336+
tools: {
337+
deny: ["browser"],
338+
},
339+
},
340+
},
341+
};
342+
343+
const message = formatSandboxToolPolicyBlockedMessage({
344+
cfg,
345+
sessionKey,
346+
toolName: "browser",
347+
});
348+
349+
const sessionLine = message?.split("\n").find((line) => line.startsWith("Session: "));
350+
const sessionLabel = sessionLine?.slice("Session: ".length);
351+
expect(sessionLabel).toBe(expectedLabel);
352+
expect(sessionLabel?.length).toBeLessThanOrEqual(13);
353+
expect(sessionLabel).not.toMatch(
354+
/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/u,
355+
);
356+
expect(message).toContain(`openclaw sandbox explain --session '${sessionKey}'`);
357+
});
358+
308359
it("avoids terminal injection for control-character session keys", () => {
309360
const sessionKey = "agent:main:abcde\n12345";
310361
const cfg: OpenClawConfig = {

0 commit comments

Comments
 (0)