Skip to main content
ISSUE-309CriticalCI/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.