Skip to main content
ISSUE-309CriticalQuickCLICI/CD Secrets

Workflow exposes all its secrets at once

Control: Workflows must not expose all secrets at once· Config key: workflowMustNotExportEntireSecretsContext

📋 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
# .plumber.yaml
github:
controls:
workflowMustNotExportEntireSecretsContext:
enabled: true

💡 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.

⚙️ Configuration

This control is configured in .plumber.yaml under the github section:

github:
  controls:
    workflowMustNotExportEntireSecretsContext:
      enabled: true

See the CLI documentation for the full configuration reference.