C.W.K.
Stream
Lesson 02 of 12 · published

Using Secrets Safely

~13 min · secrets, redaction, leakage

Level 0Apprentice
0 XP0/101 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

GitHub auto-redacts, but only what it knows

GitHub redacts the literal value of a secret from all log output. If a secret is sk-abc123, every appearance of that string in stdout, stderr, command output, error messages, or annotations gets replaced with ***.

But redaction is literal string match. It cannot redact:

  • Encoded versions — base64'd secrets, JSON-escaped secrets, URL-encoded secrets are not the literal string and are not redacted.
  • Derived values — JWT signed with the secret, hashes of the secret. These don't equal the secret but can leak it.
  • Partial echoes — if your script prints the first 10 chars only, those 10 chars don't trigger redaction.
  • Secrets from env in nested processes if you set set -x (bash debug mode) — bash echoes the entire environment.

Defensive habits

  1. Pass secrets via env:, never via shell command-line arguments (those show up in process listings on multi-tenant CI).
  2. Never echo a secret-containing variable, even for debug.
  3. Pipe sensitive output through --mask: echo "::add-mask::$VALUE" tells GitHub to redact.
  4. Avoid set -x in any block that touches secrets.
  5. For multi-line secrets (RSA keys), prefer file-based handoff: write to a file with umask 077 and reference by path.

Code

Right and wrong ways to use a secret·yaml
# WRONG — exposes the secret in process list
      - run: |
          curl -H "Authorization: Bearer ${{ secrets.TOKEN }}" https://api.example.com

# RIGHT — env var, no echo, no command-line
      - env:
          TOKEN: ${{ secrets.TOKEN }}
        run: |
          curl -H "Authorization: Bearer $TOKEN" https://api.example.com

# RIGHT — file handoff for multi-line secrets
      - env:
          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
        run: |
          umask 077
          printf '%s\n' "$DEPLOY_KEY" > /tmp/key
          ssh -i /tmp/key user@host 'uptime'

External links

Exercise

Search your existing workflows for any echo $SOMETHING where SOMETHING is a secret. Replace with the file-handoff or env-var-no-echo pattern. Push and verify logs no longer show the secret value (even partially).

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.