Secrets Outside Env

Secrets Used Outside Environment Variables

Description

Interpolating a secret directly into a run: command — deploy --token ${{ secrets.TOKEN }} — places the plaintext value on the command line, where it can leak through process listings (ps), shell traces (set -x), error output, or logs that are not perfectly masked. 1 The recommended pattern is to pass the secret through a step env: variable and reference the environment variable in the command, which keeps the value out of the command line. Self-hosted runners have an even higher-impact variant covered by Self Hosted Runner Secrets in Run.

Vulnerable Instance

  • A run: step interpolates ${{ secrets.* }} directly into the command text.
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - run: curl -H "Authorization: Bearer ${{ secrets.API_TOKEN }}" https://api.example.com
        # token appears on the command line / process list

Mitigation Strategies

  1. Pass secrets via env:. Bind the secret to a step environment variable and reference $VAR in the command.

    - env:
        API_TOKEN: ${{ secrets.API_TOKEN }}
      run: curl -H "Authorization: Bearer $API_TOKEN" https://api.example.com
  2. Quote the variable ("$API_TOKEN") and avoid echoing it.

  3. Disable command tracing around secret usage (avoid set -x where secrets are handled).

Secure Version

     steps:
-      - run: curl -H "Authorization: Bearer ${{ secrets.API_TOKEN }}" https://api.example.com
+      - env:
+          API_TOKEN: ${{ secrets.API_TOKEN }}
+        run: curl -H "Authorization: Bearer $API_TOKEN" https://api.example.com

Impact

DimensionSeverityNotes
LikelihoodMediumA very common shortcut when wiring up API calls in run steps.
RiskMediumIncreases the chance a secret leaks via process listings, traces, or imperfectly masked logs.
Blast radiusModerateLimited to the exposed credential, but that credential may be high value.

References


Last updated on