Skip to content

fix(security): sanitize file paths in log messages to prevent GitHub Actions workflow command injection#2925

Open
BiswajeetRay7 wants to merge 1 commit into
google:mainfrom
BiswajeetRay7:security/log-injection-workflow-commands
Open

fix(security): sanitize file paths in log messages to prevent GitHub Actions workflow command injection#2925
BiswajeetRay7 wants to merge 1 commit into
google:mainfrom
BiswajeetRay7:security/log-injection-workflow-commands

Conversation

@BiswajeetRay7

Copy link
Copy Markdown

Problem

Several log sites in osv-scanner echo file paths derived from filesystem walk of the scanned repository without applying output.SanitizeForWorkflowCommand. On Linux, file names may contain \r/\n bytes and git tracks such files, so an attacker-controlled repository (typically via pull_request-triggered google/osv-scanner-action) could inject ::add-mask::, ::stop-commands::, ::error::, etc. into the runner's stdout.

Prior art in the same repository

pkg/osvscanner/scan.go:158 already applies the correct guard for the directory-name log line, and its source comment explains the exact threat model:

// path is user-controlled and is logged to stdout, which the GitHub Actions
// runner parses for ::command::value sequences regardless of --format.
// Sanitize \r/\n so an attacker-supplied directory name cannot inject
// workflow commands.
cmdlogger.Infof("Scanning dir %s", output.SanitizeForWorkflowCommand(path))

Fix

Extend the same guard to the remaining unsanitized sites:

  • internal/config/manager.go:57,61 — config LoadPath / configPath (derived from lockfile path via Manager.Get(loc)normalizeConfigLoadPath)
  • internal/config/config.go:164LoadPath on duplicate-ignores warning
  • pkg/osvscanner/osvscanner.go:401configFile on unused-ignores warning
  • internal/sourceanalysis/rust.go:55,62,73 — Rust binary path in analysis errors

Related VRP report

https://issuetracker.google.com/issues/533784193

No behaviour change for benign paths

SanitizeForWorkflowCommand is an identity function on strings that contain no \r or \n, so no CI or user-visible output changes for typical file paths.

…Actions workflow command injection

Several log sites echo file paths derived from filesystem walk of the
scanned repository without applying output.SanitizeForWorkflowCommand.
On Linux file names may contain \r/\n bytes and git tracks such files,
so an attacker-controlled repository (typically via pull_request-triggered
osv-scanner-action) could inject ::add-mask::, ::stop-commands::, ::error::,
etc. into the runner's stdout.

pkg/osvscanner/scan.go:158 already applies the correct guard for the
directory-name log line and its source comment explains the threat model.
This change extends the same guard to the remaining unsanitized sites:

  - internal/config/manager.go:57,61  (config LoadPath / configPath)
  - internal/config/config.go:164     (LoadPath on duplicate-ignores warning)
  - pkg/osvscanner/osvscanner.go:401  (configFile on unused-ignores warning)
  - internal/sourceanalysis/rust.go:55,62,73 (rust binary path in analysis errors)

Refs: https://issuetracker.google.com/issues/533784193
@adilburaksen

Copy link
Copy Markdown

While looking at this, I noticed the same threat model also reaches a set of package-identity log sinks that this PR doesn't cover — ones that read the package name / version / ecosystem from lockfile or SBOM contents rather than from a file path. There's no global guard (the cmdlogger handler writes record.Message verbatim to stdout), so each needs the same SanitizeForWorkflowCommand treatment as pkg/osvscanner/scan.go:158:

  • pkg/osvscanner/filter.go:48 — short-commit skip warning (imodels.Name). Reachable with no config via a git dependency whose commit hash is < 40 chars.
  • pkg/osvscanner/filter.go:104 — ignored-package notice (pkgString = ecosystem/name/version, plus reason).
  • pkg/osvscanner/vulnerability_result.go:110,113 — license-override notices.

A package name can legally contain \r/\n (e.g. a package-lock.json packages path key, or a CycloneDX component), so this is injectable with only crafted lockfile contents — no unusual filenames needed. I have a small patch for these that's tested (go test ./pkg/osvscanner/ passes, no snapshot changes; sanitizer is identity on clean strings). Happy to fold it into this PR or send it separately if you'd prefer — whichever fits your process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants