mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-18 06:47:28 +00:00
fix(exec): honor shell comments in allow-always analysis
This commit is contained in:
@@ -303,6 +303,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Nodes/system.run PowerShell wrapper parsing: treat `pwsh`/`powershell` `-EncodedCommand` forms as shell-wrapper payloads so allowlist mode still requires approval instead of falling back to plain argv analysis. Thanks @tdjackey for reporting.
|
||||
- Control UI/auth error reporting: map generic browser `Fetch failed` websocket close errors back to actionable gateway auth messages (`gateway token mismatch`, `authentication failed`, `retry later`) so dashboard disconnects stop hiding credential problems. Landed from contributor PR #28608 by @KimGLee. Thanks @KimGLee.
|
||||
- Media/mime unknown-kind handling: return `undefined` (not `"unknown"`) for missing/unrecognized MIME kinds and use document-size fallback caps for unknown remote media, preventing phantom `<media:unknown>` Signal events from being treated as real messages. (#39199) Thanks @nicolasgrasset.
|
||||
- Nodes/system.run allow-always persistence: honor shell comment semantics during allowlist analysis so `#`-tailed payloads that never execute are not persisted as trusted follow-up commands. Thanks @tdjackey for reporting.
|
||||
|
||||
## 2026.3.2
|
||||
|
||||
|
||||
@@ -302,4 +302,21 @@ describe("resolveAllowAlwaysPatterns", () => {
|
||||
persistedPattern: echo,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not persist comment-tailed payload paths that never execute", () => {
|
||||
if (process.platform === "win32") {
|
||||
return;
|
||||
}
|
||||
const dir = makeTempDir();
|
||||
const benign = makeExecutable(dir, "benign");
|
||||
makeExecutable(dir, "payload");
|
||||
const env = makePathEnv(dir);
|
||||
expectAllowAlwaysBypassBlocked({
|
||||
dir,
|
||||
firstCommand: `${benign} warmup # && payload`,
|
||||
secondCommand: "payload",
|
||||
env,
|
||||
persistedPattern: benign,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -59,6 +59,17 @@ function isEscapedLineContinuation(next: string | undefined): next is string {
|
||||
return next === "\n" || next === "\r";
|
||||
}
|
||||
|
||||
function isShellCommentStart(source: string, index: number): boolean {
|
||||
if (source[index] !== "#") {
|
||||
return false;
|
||||
}
|
||||
if (index === 0) {
|
||||
return true;
|
||||
}
|
||||
const prev = source[index - 1];
|
||||
return Boolean(prev && /\s/.test(prev));
|
||||
}
|
||||
|
||||
function splitShellPipeline(command: string): { ok: boolean; reason?: string; segments: string[] } {
|
||||
type HeredocSpec = {
|
||||
delimiter: string;
|
||||
@@ -246,6 +257,9 @@ function splitShellPipeline(command: string): { ok: boolean; reason?: string; se
|
||||
emptySegment = false;
|
||||
continue;
|
||||
}
|
||||
if (isShellCommentStart(command, i)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ch === "\n" || ch === "\r") && pendingHeredocs.length > 0) {
|
||||
inHeredocBody = true;
|
||||
@@ -501,6 +515,9 @@ export function splitCommandChainWithOperators(command: string): ShellChainPart[
|
||||
buf += ch;
|
||||
continue;
|
||||
}
|
||||
if (isShellCommentStart(command, i)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch === "&" && next === "&") {
|
||||
if (!pushPart("&&")) {
|
||||
|
||||
@@ -59,6 +59,10 @@ export function splitShellArgs(raw: string): string[] | null {
|
||||
inDouble = true;
|
||||
continue;
|
||||
}
|
||||
// In POSIX shells, "#" starts a comment only when it begins a word.
|
||||
if (ch === "#" && buf.length === 0) {
|
||||
break;
|
||||
}
|
||||
if (/\s/.test(ch)) {
|
||||
pushToken();
|
||||
continue;
|
||||
|
||||
@@ -106,4 +106,10 @@ describe("splitShellArgs", () => {
|
||||
expect(splitShellArgs(`echo "oops`)).toBeNull();
|
||||
expect(splitShellArgs(`echo 'oops`)).toBeNull();
|
||||
});
|
||||
|
||||
it("stops at unquoted shell comments but keeps quoted hashes literal", () => {
|
||||
expect(splitShellArgs(`echo hi # comment && whoami`)).toEqual(["echo", "hi"]);
|
||||
expect(splitShellArgs(`echo "hi # still-literal"`)).toEqual(["echo", "hi # still-literal"]);
|
||||
expect(splitShellArgs(`echo hi#tail`)).toEqual(["echo", "hi#tail"]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user