Skip to content

Safe-output artifacts can expose base64 CI trigger tokens #50616

Description

@PureWeen

Summary

In gh-aw v0.84.3, generated safe_outputs jobs upload raw process-safe-outputs.stdout.log and .stderr.log. For workflows that use create-pull-request or push-to-pull-request-branch with GH_AW_CI_TRIGGER_TOKEN, those artifacts contain a reversible base64-encoded authorization header.

Verified execution path

  1. The compiler injects GH_AW_CI_TRIGGER_TOKEN for patch-capable safe outputs: compiler_safe_outputs_steps.go L223-L243.
  2. git_auth_helpers.cjs constructs Authorization: basic <base64(x-access-token:TOKEN)> and passes it to unsilenced exec.exec("git", ...): git_auth_helpers.cjs L108-L121.
  3. @actions/exec defaults to silent: false and writes the complete command line, including arguments, to stdout: toolrunner.ts L353-L366 and L420-L425.
  4. process_safe_outputs.cjs tees stdout/stderr to files before forwarding the bytes to the GitHub runner: process_safe_outputs.cjs L35-L70.
  5. The compiler uploads both raw files unconditionally: compiler_safe_outputs_job.go L944-L957.

The derived base64 value is not registered for masking. More importantly, runner masking cannot protect the local file because the wrapper writes it before the runner receives stdout. The authorization value is trivially reversible with base64 -d.

Scope

The exposure requires a configured nonempty CI-trigger token and a normal same-repository create/push safe-output path. Staged, cross-repository, or skipped paths do not reach it. Artifact access and token lifetime determine the practical blast radius.

Expected behavior

No credential-bearing command line should be captured in uploaded artifacts.

Suggested remediation

One of the following is needed:

  • Add { silent: true } to the credential-bearing git config calls in git_auth_helpers.cjs.
  • Redact credential-bearing chunks inside process_safe_outputs.cjs before writing its artifact files.
  • Stop uploading the raw process-safe-output stdout/stderr logs until credential handling is safe.

core.setSecret() alone is insufficient because these files are written before runner-side masking.

Affected generated workflow consumers should regenerate their locks after a fixed stable release is available.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions