diff --git a/tools/skillgen/fragments/shell/posix.md b/tools/skillgen/fragments/shell/posix.md index 3534417d2..ed0c555aa 100644 --- a/tools/skillgen/fragments/shell/posix.md +++ b/tools/skillgen/fragments/shell/posix.md @@ -30,8 +30,14 @@ fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out "$PYTHON" -c "import sys; open('graphify-out/.graphify_python', 'w', encoding='utf-8').write(sys.executable)" -# Save scan root so `graphify update` (no args) knows where to look next time -echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root +# Save scan root so `graphify update` (no args) knows where to look next time. +# INPUT_PATH is passed through a quoted heredoc, never substituted into the +# command line itself: a bare `cd INPUT_PATH` (or an unquoted heredoc, which +# still expands $()/backticks in its body) would let a malicious path execute +# as shell code the moment this line runs. +"$PYTHON" -c "import os, sys; out_path = os.path.abspath('graphify-out/.graphify_root'); os.chdir(sys.stdin.readline().rstrip('\n')); open(out_path, 'w', encoding='utf-8').write(os.getcwd())" <<'GRAPHIFY_ROOT_EOF' +INPUT_PATH +GRAPHIFY_ROOT_EOF ``` If the import succeeds, print nothing and move straight to Step 2. diff --git a/tools/skillgen/fragments/shell/powershell.md b/tools/skillgen/fragments/shell/powershell.md index 71e493cf8..7837595ea 100644 --- a/tools/skillgen/fragments/shell/powershell.md +++ b/tools/skillgen/fragments/shell/powershell.md @@ -57,8 +57,15 @@ if (-not $GRAPHIFY_PYTHON) { # encoding writes the bytes POSIX writes, and adds no trailing newline. $Utf8NoBom = New-Object System.Text.UTF8Encoding $false [System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_python'), [string]$GRAPHIFY_PYTHON, $Utf8NoBom) -# Save scan root so `graphify update` (no args) knows where to look next time -[System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_root'), (Resolve-Path INPUT_PATH).Path, $Utf8NoBom) +# Save scan root so `graphify update` (no args) knows where to look next time. +# INPUT_PATH is captured through a single-quoted (literal) here-string, never +# substituted directly into the command line: an unquoted bareword argument +# substituted here would let a malicious path (a stray `;`, `|`, or `$(...)`) +# execute as script code the moment this line runs. +$InputPathRaw = @' +INPUT_PATH +'@ +[System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_root'), (Resolve-Path $InputPathRaw.Trim()).Path, $Utf8NoBom) ``` If the import succeeds, print nothing and move straight to Step 2.