Skip to content

Commit b2eed5e

Browse files
committed
fix: block commands that exceed recursion depth
Previously, commands exceeding MAX_RECURSION_DEPTH returned null which allowed them through. Now they are blocked with a clear reason message. Also increases MAX_RECURSION_DEPTH from 5 to 10 to handle more deeply nested shell wrapper commands.
1 parent 54ceb94 commit b2eed5e

File tree

3 files changed

+14
-15
lines changed

3 files changed

+14
-15
lines changed

src/core/analyze/analyze-command.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import { analyzeSegment, segmentChangesCwd } from './segment.ts';
1313
const REASON_STRICT_UNPARSEABLE =
1414
'Command could not be safely analyzed (strict mode). Verify manually.';
1515

16+
const REASON_RECURSION_LIMIT =
17+
'Command exceeds maximum recursion depth and cannot be safely analyzed.';
18+
1619
export type InternalOptions = AnalyzeOptions & { config: Config };
1720

1821
export function analyzeCommandInternal(
@@ -21,7 +24,7 @@ export function analyzeCommandInternal(
2124
options: InternalOptions,
2225
): AnalyzeResult | null {
2326
if (depth >= MAX_RECURSION_DEPTH) {
24-
return null;
27+
return { reason: REASON_RECURSION_LIMIT, segment: command };
2528
}
2629

2730
const segments = splitShellCommands(command);

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export interface AuditLogEntry {
116116
}
117117

118118
/** Constants */
119-
export const MAX_RECURSION_DEPTH = 5;
119+
export const MAX_RECURSION_DEPTH = 10;
120120
export const MAX_STRIP_ITERATIONS = 20;
121121

122122
export const NAME_PATTERN = /^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/;

tests/edge-cases.test.ts

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -643,13 +643,12 @@ describe('edge cases', () => {
643643
});
644644

645645
describe('recursion', () => {
646-
test('shell dash c recursion limit reached returns null', () => {
646+
test('shell dash c recursion limit reached blocks command', () => {
647647
let cmd = 'rm -rf /some/path';
648-
for (let i = 0; i < 6; i++) {
648+
for (let i = 0; i < 11; i++) {
649649
cmd = `bash -c ${JSON.stringify(cmd)}`;
650650
}
651-
const result = runGuard(cmd);
652-
expect(result).toBeNull();
651+
assertBlocked(cmd, 'recursion');
653652
});
654653
});
655654

@@ -714,23 +713,20 @@ describe('edge cases', () => {
714713
});
715714

716715
describe('recursion depth boundary', () => {
717-
test('shell dash c recursion at exactly MAX_RECURSION_DEPTH (5) returns null', () => {
716+
test('shell dash c recursion at exactly MAX_RECURSION_DEPTH (10) blocks', () => {
718717
let cmd = 'rm -rf /some/path';
719-
for (let i = 0; i < 5; i++) {
718+
for (let i = 0; i < 10; i++) {
720719
cmd = `bash -c ${JSON.stringify(cmd)}`;
721720
}
722-
const result = runGuard(cmd);
723-
expect(result).toBeNull();
721+
assertBlocked(cmd, 'recursion');
724722
});
725723

726-
test('shell dash c recursion at depth 4 still blocks', () => {
724+
test('shell dash c recursion at depth 9 still blocks with rm reason', () => {
727725
let cmd = 'rm -rf /some/path';
728-
for (let i = 0; i < 4; i++) {
726+
for (let i = 0; i < 9; i++) {
729727
cmd = `bash -c ${JSON.stringify(cmd)}`;
730728
}
731-
const result = runGuard(cmd);
732-
expect(result).not.toBeNull();
733-
expect(result).toContain('rm -rf');
729+
assertBlocked(cmd, 'rm -rf');
734730
});
735731
});
736732

0 commit comments

Comments
 (0)