diff --git a/.github/workflows/secret-scan.yml b/.github/workflows/secret-scan.yml index 2d1e557e..cebf89e9 100644 --- a/.github/workflows/secret-scan.yml +++ b/.github/workflows/secret-scan.yml @@ -148,7 +148,13 @@ jobs: SELF=".github/workflows/secret-scan.yml" OFFENDING="" - for f in $CHANGED; do + # `while IFS= read -r` (not `for f in $CHANGED`) so filenames + # containing whitespace don't word-split silently — a path + # with a space would otherwise produce two iterations on + # tokens that aren't real filenames, breaking the + # self-exclude + diff lookup. + while IFS= read -r f; do + [ -z "$f" ] && continue [ "$f" = "$SELF" ] && continue if [ -n "$DIFF_RANGE" ]; then ADDED=$(git diff --no-color --unified=0 "$BASE" "$HEAD" -- "$f" 2>/dev/null | grep -E '^\+[^+]' || true) @@ -164,11 +170,18 @@ jobs: break fi done - done + done <<< "$CHANGED" if [ -n "$OFFENDING" ]; then echo "::error::Credential-shaped strings detected in diff additions:" - printf "$OFFENDING" + # `printf '%b' "$OFFENDING"` interprets backslash escapes + # (the literal `\n` we appended above becomes a newline) + # WITHOUT treating OFFENDING as a format string. Plain + # `printf "$OFFENDING"` is a format-string sink: a filename + # containing `%` would be interpreted as a conversion + # specifier, corrupting the error message (or printing + # `%(missing)` artifacts). + printf '%b' "$OFFENDING" echo "" echo "The actual matched values are NOT echoed here, deliberately —" echo "round-tripping a leaked credential into CI logs widens the blast"