MCPcopy Index your code
hub / github.com/codeaashu/claude-code / validateOutputRedirections

Function validateOutputRedirections

src/tools/BashTool/pathValidation.ts:924–1003  ·  view source on GitHub ↗
(
  redirections: Array<{ target: string; operator: '>' | '>>' }>,
  cwd: string,
  toolPermissionContext: ToolPermissionContext,
  compoundCommandHasCd?: boolean,
)

Source from the content-addressed store, hash-verified

922}
923
924function validateOutputRedirections(
925 redirections: Array<{ target: string; operator: '>' | '>>' }>,
926 cwd: string,
927 toolPermissionContext: ToolPermissionContext,
928 compoundCommandHasCd?: boolean,
929): PermissionResult {
930 // SECURITY: Block output redirections in compound commands containing 'cd'
931 // This prevents bypassing path safety checks via directory changes before redirections.
932 // Example attack: cd .claude/ && echo "malicious" > settings.json
933 // The redirection target would be validated relative to the original CWD, but the
934 // actual write happens in the changed directory after 'cd' executes.
935 if (compoundCommandHasCd && redirections.length > 0) {
936 return {
937 behavior: 'ask',
938 message: `Commands that change directories and write via output redirection require explicit approval to ensure paths are evaluated correctly. For security, Claude Code cannot automatically determine the final working directory when 'cd' is used in compound commands.`,
939 decisionReason: {
940 type: 'other',
941 reason:
942 'Compound command contains cd with output redirection - manual approval required to prevent path resolution bypass',
943 },
944 }
945 }
946 for (const { target } of redirections) {
947 // /dev/null is always safe - it discards output
948 if (target === '/dev/null') {
949 continue
950 }
951 const { allowed, resolvedPath, decisionReason } = validatePath(
952 target,
953 cwd,
954 toolPermissionContext,
955 'create', // Treat > and >> as create operations
956 )
957
958 if (!allowed) {
959 const workingDirs = Array.from(
960 allWorkingDirectories(toolPermissionContext),
961 )
962 const dirListStr = formatDirectoryList(workingDirs)
963
964 // Use security check's custom reason if available (type: 'other' or 'safetyCheck')
965 // Otherwise use the standard message for deny rules or working directory restrictions
966 const message =
967 decisionReason?.type === 'other' ||
968 decisionReason?.type === 'safetyCheck'
969 ? decisionReason.reason
970 : decisionReason?.type === 'rule'
971 ? `Output redirection to '${resolvedPath}' was blocked by a deny rule.`
972 : `Output redirection to '${resolvedPath}' was blocked. For security, Claude Code may only write to files in the allowed working directories for this session: ${dirListStr}.`
973
974 // If denied by a deny rule, return 'deny' behavior
975 if (decisionReason?.type === 'rule') {
976 return {
977 behavior: 'deny',
978 message,
979 decisionReason,
980 }
981 }

Callers 1

checkPathConstraintsFunction · 0.85

Calls 4

allWorkingDirectoriesFunction · 0.85
getDirectoryForPathFunction · 0.85
validatePathFunction · 0.50
formatDirectoryListFunction · 0.50

Tested by

no test coverage detected