MCPcopy Create free account
hub / github.com/AnukarOP/claude-code-leaked / resolveSimpleExpansion

Function resolveSimpleExpansion

source code/utils/bash/ast.ts:1939–2010  ·  view source on GitHub ↗

* Resolve a `simple_expansion` ($VAR) node. Returns VAR_PLACEHOLDER if * resolvable, too-complex otherwise. * * @param insideString true when $VAR is inside a `string` node ("...$VAR...") * rather than a bare/concatenation argument. SAFE_ENV_VARS and unknown-value * tracked vars are only al

(
  node: Node,
  varScope: Map<string, string>,
  insideString: boolean,
)

Source from the content-addressed store, hash-verified

1937 * value IS known.
1938 */
1939function resolveSimpleExpansion(
1940 node: Node,
1941 varScope: Map<string, string>,
1942 insideString: boolean,
1943): string | ParseForSecurityResult {
1944 let varName: string | null = null
1945 let isSpecial = false
1946 for (const c of node.children) {
1947 if (c?.type === 'variable_name') {
1948 varName = c.text
1949 break
1950 }
1951 if (c?.type === 'special_variable_name') {
1952 varName = c.text
1953 isSpecial = true
1954 break
1955 }
1956 }
1957 if (varName === null) return tooComplex(node)
1958 // Tracked vars: check stored value. Literal strings (VAR=/tmp) are
1959 // returned DIRECTLY so downstream path validation sees the real path.
1960 // Non-literal values (containing any placeholder — loop vars, $() output,
1961 // read vars, composites like `VAR="prefix$(cmd)"`) are ONLY safe inside
1962 // strings; as bare args they'd hide the runtime path/flag from validation.
1963 //
1964 // SECURITY: Returning the actual trackedValue (not a placeholder) is the
1965 // critical fix. `VAR=/etc && rm $VAR` → argv ['rm', '/etc'] → validatePath
1966 // correctly rejects. Previously returned a placeholder → validatePath saw
1967 // '__LOOP_STATIC__', resolved as cwd-relative → PASSED → bypass.
1968 const trackedValue = varScope.get(varName)
1969 if (trackedValue !== undefined) {
1970 if (containsAnyPlaceholder(trackedValue)) {
1971 // Non-literal: bare → reject, inside string → VAR_PLACEHOLDER
1972 // (walkString's solo-placeholder gate rejects `"$VAR"` alone).
1973 if (!insideString) return tooComplex(node)
1974 return VAR_PLACEHOLDER
1975 }
1976 // Pure literal (e.g. '/tmp', 'foo') — return it directly. Downstream
1977 // path validation / checkSemantics operate on the REAL value.
1978 //
1979 // SECURITY: For BARE args (not inside a string), bash word-splits on
1980 // $IFS and glob-expands the result. `VAR="-rf /" && rm $VAR` → bash
1981 // runs `rm -rf /` (two args); `VAR="/etc/*" && cat $VAR` → expands to
1982 // all files. Reject values containing IFS/glob chars unless in "...".
1983 //
1984 // SECURITY: Empty value as bare arg. Bash word-splitting on "" produces
1985 // ZERO fields — the expansion disappears. `V="" && $V eval x` → bash
1986 // runs `eval x` (our argv would be ["","eval","x"] with name="" —
1987 // every EVAL_LIKE/ZSH/keyword check misses). `V="" && ls $V /etc` →
1988 // bash runs `ls /etc`, our argv has a phantom "" shifting positions.
1989 // Inside "...": `"$V"` → bash produces one empty-string arg → our ""
1990 // is correct, keep allowing.
1991 if (!insideString) {
1992 if (trackedValue === '') return tooComplex(node)
1993 if (BARE_VAR_UNSAFE_RE.test(trackedValue)) return tooComplex(node)
1994 }
1995 return trackedValue
1996 }

Callers 4

walkCommandFunction · 0.85
walkArgumentFunction · 0.85
walkStringFunction · 0.85
walkVariableAssignmentFunction · 0.85

Calls 4

tooComplexFunction · 0.85
containsAnyPlaceholderFunction · 0.85
getMethod · 0.45
hasMethod · 0.45

Tested by

no test coverage detected