Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2b0a8c2

Browse files
mksgluclaude
andcommitted
fix: post-merge fixes for PRs mksglu#183, mksglu#190, mksglu#192
PR mksglu#183: Restrict sessionKey regex to [a-zA-Z0-9_-]+ and add startsWith containment check to prevent path traversal in writeRoutingInstructions workspace derivation. PR mksglu#190: Fix getRuntimeSummary() bun detection — use endsWith("bun") instead of === "bun" to handle full paths like ~/.bun/bin/bun. PR mksglu#192: Remove trailing whitespace from AGENTS.md blank separator lines. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
1 parent f69b0d2 commit 2b0a8c2

4 files changed

Lines changed: 45 additions & 10 deletions

File tree

configs/codex/AGENTS.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,20 @@ Search results can flood context. Use `ctx_execute(language: "shell", code: "gre
5858
| `ctx upgrade` | Call the `upgrade` MCP tool, run the returned shell command, display as checklist |
5959

6060
## Windows notes
61-
61+
6262
**PowerShell cmdlets in shell scripts** — The sandbox executes scripts via bash. PowerShell
6363
cmdlets (`Format-List`, `Format-Table`, `Get-Culture`, etc.) do not exist in bash and will fail
6464
with `command not found`. Wrap them with `pwsh -NoProfile -Command "..."` instead.
65-
65+
6666
**Relative paths** — The sandbox CWD is a temp directory, not your project root. Always convert
6767
any user-supplied path to an absolute path before passing it to `rg`, `grep`, or `find`.
6868
Ask the user to confirm the absolute path if it is not already known.
69-
69+
7070
**Windows drive letter paths** — The sandbox runs Git Bash / MSYS2, not WSL. Drive letters must
7171
use the MSYS2 convention, NOT the WSL convention:
7272
`X:\path``/x/path` (lowercase letter, no `/mnt/` prefix).
7373
Never emit `/mnt/<letter>/` prefixes regardless of which drive the project is on.
74-
74+
7575
**Always quote paths** — If a path contains spaces, bash splits it into separate arguments.
7676
Always wrap every path in double quotes: `rg "symbol" "$REPO_ROOT/some dir/Source"`.
7777
This applies to all tools: `rg`, `grep`, `find`, `ls`, etc.

src/openclaw-plugin.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -494,14 +494,18 @@ export default {
494494
if (key) {
495495
try {
496496
const adapter = new OpenClawAdapter();
497+
const openclawBase = resolve(homedir(), ".openclaw");
497498
// Resolve workspace dir from sessionKey (pattern: agent:<name>:*)
498-
const wsMatch = key.match(/^agent:([^:]+):/);
499+
// Restrict agent name to safe characters to prevent path traversal (#183)
500+
const wsMatch = key.match(/^agent:([a-zA-Z0-9_-]+):/);
501+
let wsDir: string;
499502
if (wsMatch) {
500-
const wsDir = resolve(homedir(), ".openclaw", `workspace-${wsMatch[1]}`);
501-
adapter.writeRoutingInstructions(wsDir, pluginRoot);
503+
wsDir = resolve(openclawBase, `workspace-${wsMatch[1]}`);
502504
} else {
503-
// Fallback: main workspace (sessionKey doesn't follow agent:<name>: pattern)
504-
const wsDir = resolve(homedir(), ".openclaw", "workspace");
505+
wsDir = resolve(openclawBase, "workspace");
506+
}
507+
// Containment check: never write outside ~/.openclaw/
508+
if (wsDir.startsWith(openclawBase)) {
505509
adapter.writeRoutingInstructions(wsDir, pluginRoot);
506510
}
507511
} catch {

src/runtime.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export function hasBunRuntime(): boolean {
150150

151151
export function getRuntimeSummary(runtimes: RuntimeMap): string {
152152
const lines: string[] = [];
153-
const bunPreferred = runtimes.javascript === "bun";
153+
const bunPreferred = runtimes.javascript?.endsWith("bun") ?? false;
154154

155155
lines.push(
156156
` JavaScript: ${runtimes.javascript} (${getVersion(runtimes.javascript)})${bunPreferred ? " ⚡" : ""}`,

tests/core/cli.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,3 +819,34 @@ describe("Self-heal covers all hook types (#187)", () => {
819819
expect(selfHealSection).toContain("context-mode");
820820
});
821821
});
822+
823+
// ── PR #183 fix: path traversal prevention in OpenClaw sessionKey ──
824+
825+
describe("OpenClaw sessionKey safety (#183)", () => {
826+
const OC_SOURCE = readFileSync(resolve(ROOT, "src/openclaw-plugin.ts"), "utf-8");
827+
828+
test("sessionKey regex only allows safe characters (no path traversal)", () => {
829+
// Must use [a-zA-Z0-9_-]+ not [^:]+ to prevent ../../ in agent name
830+
expect(OC_SOURCE).toContain('[a-zA-Z0-9_-]+');
831+
expect(OC_SOURCE).not.toMatch(/\[\^:\]\+/);
832+
});
833+
834+
test("workspace path has containment check against .openclaw base", () => {
835+
// Must verify resolved path stays inside ~/.openclaw/
836+
expect(OC_SOURCE).toContain('startsWith(');
837+
expect(OC_SOURCE).toContain('.openclaw');
838+
});
839+
});
840+
841+
// ── PR #190 fix: getRuntimeSummary handles full bun path ──
842+
843+
describe("Runtime summary bun detection (#190)", () => {
844+
const RT_SOURCE = readFileSync(resolve(ROOT, "src/runtime.ts"), "utf-8");
845+
846+
test("getRuntimeSummary does not use exact === bun comparison", () => {
847+
// Full path like /home/user/.bun/bin/bun must be detected
848+
const summaryStart = RT_SOURCE.indexOf("getRuntimeSummary");
849+
const summaryBody = RT_SOURCE.slice(summaryStart, RT_SOURCE.indexOf("\nexport", summaryStart + 10));
850+
expect(summaryBody).not.toContain('=== "bun"');
851+
});
852+
});

0 commit comments

Comments
 (0)