Skip to main content
ISSUE-309CriticalCI/CD Secrets

Workflow exposes all its secrets at once

Control:CTRL-309Workflows must not expose all secrets at once

📋 What is this?

A GitHub Actions workflow serialises the whole secrets context with toJson(secrets) or toJSON(secrets) and pipes the result into a step's environment, run: script, or with: input. The resulting string contains every secret the job has access to (repository, organisation and environment) and travels through whatever downstream consumer the step passes it to (a third-party action, a remote server, a log line). Even with GitHub's automatic log redaction, a single echo of the JSON payload has been enough to leak tokens in past supply-chain incidents; a compromised reusable action sees them directly regardless of logging.

⚠️ Impact

GitHub's redactor masks known secret strings in logs. A toJson(secrets) dump produces a single JSON value containing every secret as a substring of a larger string; the redactor does not recognise the wrapping and the secrets leak verbatim. The risk compounds when the dump is forwarded to anything outside GitHub's runtime: a curl, a docker run, a scratch file picked up by an artifact upload.

🔧 How to fix

Pass only the specific secrets the step needs, by name: env: { TOKEN: ${{ secrets.NPM_TOKEN }} }. If the step forwards credentials to a reusable workflow, name each one in the secrets: block of the call rather than using toJson(secrets) or secrets: inherit.

✗ BeforeThe aggregated JSON appears unredacted in logs and on disk.
# .github/workflows/deploy.yml: ❌ Aggregated secrets dump
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- env:
ALL_SECRETS: ${{ toJson(secrets) }}
run: echo "$ALL_SECRETS" > /tmp/sec.json && ./debug.sh /tmp/sec.json
✓ AfterEach secret stays a separate, redactable string.
# .github/workflows/deploy.yml: ✅ Scoped per-secret
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: aws s3 sync . s3://my-bucket

💡 Tips

  • Same shape as ISSUE-213 (github-context dump) but with secrets, so it is one severity higher.
  • If you genuinely need to enumerate secrets (rare), do it inside an environment: with a required reviewer and revoke afterward.

⚙️ Configure this control

With the CLI alone: set it in your configuration file. Every field and default is in the controls configuration reference, CTRL-309.