Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions packages/core/src/policy/policy-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,12 +288,14 @@ export class PolicyEngine {
if (allowRedirection) return false;
if (!hasRedirection(command)) return false;

// Do not downgrade (do not ask user) if in AUTO_EDIT or YOLO mode.
// These modes trust the agent's actions (YOLO) or specific task (AUTO_EDIT).
if (
this.approvalMode === ApprovalMode.AUTO_EDIT ||
this.approvalMode === ApprovalMode.YOLO
) {
// In YOLO mode, never downgrade.
if (this.approvalMode === ApprovalMode.YOLO) {
return false;
}

// In AUTO_EDIT mode, only bypass downgrade if sandboxing is enabled.
const sandboxEnabled = !(this.sandboxManager instanceof NoopSandboxManager);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not sure this is going to fix the issue the user is reporting, since wouldn't this still ask for approval?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

if (this.approvalMode === ApprovalMode.AUTO_EDIT && sandboxEnabled) {
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/policy/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ export function buildParamArgsPattern(
value: unknown,
): string {
const encodedValue = JSON.stringify(value);
// We wrap the JSON string in escapeRegex and prepend/append \\0 to explicitly
// We wrap the JSON string in escapeRegex and prepend/append \\x00 to explicitly
// match top-level JSON properties generated by stableStringify, preventing
// argument injection bypass attacks.
return `\\\\0${escapeRegex(`"${paramName}":${encodedValue}`)}\\\\0`;
return `\\x00${escapeRegex(`"${paramName}":${encodedValue}`)}\\x00`;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/scheduler/policy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ describe('policy.ts', () => {
expect.objectContaining({
toolName: 'write_file',
argsPattern:
'\\\\0' + escapeRegex('"file_path":"src/foo.ts"') + '\\\\0',
'\\x00' + escapeRegex('"file_path":"src/foo.ts"') + '\\x00',
}),
);
});
Expand Down
16 changes: 12 additions & 4 deletions packages/core/src/utils/shell-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -809,11 +809,11 @@ export function getCommandRoots(command: string): string[] {
}

export function stripShellWrapper(command: string): string {
const pattern =
const cFlagPattern =
/^\s*(?:(?:(?:\S+\/)?(?:sh|bash|zsh))\s+-c|cmd\.exe\s+\/c|powershell(?:\.exe)?\s+(?:-NoProfile\s+)?-Command|pwsh(?:\.exe)?\s+(?:-NoProfile\s+)?-Command)\s+/i;
const match = command.match(pattern);
if (match) {
let newCommand = command.substring(match[0].length).trim();
const cFlagMatch = command.match(cFlagPattern);
if (cFlagMatch) {
let newCommand = command.substring(cFlagMatch[0].length).trim();
if (
(newCommand.startsWith('"') && newCommand.endsWith('"')) ||
(newCommand.startsWith("'") && newCommand.endsWith("'"))
Expand All @@ -822,6 +822,14 @@ export function stripShellWrapper(command: string): string {
}
return newCommand;
}

const scriptPattern =
/^\s*(?:(?:\S+\/)?(?:sh|bash|zsh))\s+([a-zA-Z0-9_\-./]+\.sh)\s*$/i;
const scriptMatch = command.match(scriptPattern);
if (scriptMatch) {
return scriptMatch[1];
}

return command.trim();
}

Expand Down
Loading