diff --git a/src/tools/BashTool/modeValidation.ts b/src/tools/BashTool/modeValidation.ts index 2993c3e7..5e5147d1 100644 --- a/src/tools/BashTool/modeValidation.ts +++ b/src/tools/BashTool/modeValidation.ts @@ -1,8 +1,10 @@ import type { z } from 'zod/v4' import type { ToolPermissionContext } from '../../Tool.js' import { splitCommand_DEPRECATED } from '../../utils/bash/commands.js' +import { getCwd } from '../../utils/cwd.js' import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' import type { BashTool } from './BashTool.js' +import { checkDangerousRemovalPaths } from './pathValidation.js' const ACCEPT_EDITS_ALLOWED_COMMANDS = [ 'mkdir', @@ -39,6 +41,17 @@ function validateCommandForMode( toolPermissionContext.mode === 'acceptEdits' && isFilesystemCommand(baseCmd) ) { + // Guard: always run dangerous path check for rm/rmdir before auto-allowing. + // This prevents rm -rf ~ / rm -rf / from bypassing checkDangerousRemovalPaths + // which is otherwise skipped when acceptEdits returns allow early. + if (baseCmd === 'rm' || baseCmd === 'rmdir') { + const args = trimmedCmd.split(/\s+/).slice(1) + const dangerousResult = checkDangerousRemovalPaths(baseCmd, args, getCwd()) + if (dangerousResult.behavior !== 'passthrough') { + return dangerousResult + } + } + return { behavior: 'allow', updatedInput: { command: cmd }, diff --git a/src/tools/BashTool/pathValidation.ts b/src/tools/BashTool/pathValidation.ts index 8da98f8b..6fa8ca04 100644 --- a/src/tools/BashTool/pathValidation.ts +++ b/src/tools/BashTool/pathValidation.ts @@ -67,7 +67,7 @@ export type PathCommand = * require explicit user approval, even if allowlist rules exist. * This prevents catastrophic data loss from commands like `rm -rf /`. */ -function checkDangerousRemovalPaths( +export function checkDangerousRemovalPaths( command: 'rm' | 'rmdir', args: string[], cwd: string,