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

Function isStaticRedirectTarget

src/utils/bash/commands.ts:47–81  ·  view source on GitHub ↗

* Checks if a redirection target is a simple static file path that can be safely stripped. * Returns false for targets containing dynamic content (variables, command substitutions, globs, * shell expansions) which should remain visible in permission prompts for security.

(target: string)

Source from the content-addressed store, hash-verified

45 * shell expansions) which should remain visible in permission prompts for security.
46 */
47function isStaticRedirectTarget(target: string): boolean {
48 // SECURITY: A static redirect target in bash is a SINGLE shell word. After
49 // the adjacent-string collapse at splitCommandWithOperators, multiple args
50 // following a redirect get merged into one string with spaces. For
51 // `cat > out /etc/passwd`, bash writes to `out` and reads `/etc/passwd`,
52 // but the collapse gives us `out /etc/passwd` as the "target". Accepting
53 // this merged blob returns `['cat']` and pathValidation never sees the path.
54 // Reject any target containing whitespace or quote chars (quotes indicate
55 // the placeholder-restoration preserved a quoted arg).
56 if (/[\s'"]/.test(target)) return false
57 // Reject empty string — path.resolve(cwd, '') returns cwd (always allowed).
58 if (target.length === 0) return false
59 // SECURITY (parser differential hardening): shell-quote parses `#foo` at
60 // word-initial position as a comment token. In bash, `#` after whitespace
61 // also starts a comment (`> #file` is a syntax error). But shell-quote
62 // returns it as a comment OBJECT; splitCommandWithOperators maps it back to
63 // string `#foo`. This differs from extractOutputRedirections (which sees the
64 // comment object as non-string, missing the target). While `> #file` is
65 // unexecutable in bash, rejecting `#`-prefixed targets closes the differential.
66 if (target.startsWith('#')) return false
67 return (
68 !target.startsWith('!') && // No history expansion like !!, !-1, !foo
69 !target.startsWith('=') && // No Zsh equals expansion (=cmd expands to /path/to/cmd)
70 !target.includes('$') && // No variables like $HOME
71 !target.includes('`') && // No command substitution like `pwd`
72 !target.includes('*') && // No glob patterns
73 !target.includes('?') && // No single-char glob
74 !target.includes('[') && // No character class glob
75 !target.includes('{') && // No brace expansion like {1,2}
76 !target.includes('~') && // No tilde expansion
77 !target.includes('(') && // No process substitution like >(cmd)
78 !target.includes('<') && // No process substitution like <(cmd)
79 !target.startsWith('&') // Not a file descriptor like &1
80 )
81}
82
83export type { CommandPrefixResult, CommandSubcommandPrefixResult }
84

Callers 1

splitCommand_DEPRECATEDFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected