GitHub Actions Secrets Management: A Practical Guide
Learn how to store, scope, and rotate secrets in GitHub Actions. Cover repository, environment, and organization secrets, plus OIDC for cloud access without static keys.
What you'll learn
- ✓The three scopes of secrets in GitHub Actions
- ✓How to reference secrets safely from workflows
- ✓Why environment secrets and required reviewers matter
- ✓How OIDC removes the need for long-lived cloud keys
- ✓Common mistakes that leak secrets to logs
Prerequisites
- •Comfortable with the Linux command line
CI pipelines need secrets. Deploy keys, registry credentials, API tokens, database URLs — none of those belong in your repository. GitHub Actions gives you a built-in secret store with three scopes, an environments feature for approvals, and OIDC for token-based cloud access. Used together they cover almost every secret-handling case without ever shipping a credential to disk.
Where secrets live
There are three places to put a secret, in order of broadest to narrowest reach:
- Organization secrets: shared by many repositories under one org.
- Repository secrets: visible to every workflow in one repo.
- Environment secrets: visible only when a workflow runs in a specific environment, like
production.
Pick the narrowest scope that still works. A token used to publish to npm from one repo belongs in that repo, not the organization. A production database password belongs in the production environment so only deploy jobs see it.
Reading a secret in a workflow
Secrets are exposed to workflows through the secrets context. They are masked in logs automatically — but only if you reference them through the context.
name: deploy
on:
push:
branches: [main]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Publish to npm
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
npm publish
Notice that the secret is passed via an environment variable, not interpolated directly into a shell command. That is intentional. If you write run: echo ${{ secrets.NPM_TOKEN }}, GitHub substitutes the value before the shell ever sees it, which means any character in the secret can break or hijack the command. Going through env: is safer and clearer.
Environments and required reviewers
An environment is a named deployment target with its own secrets and protection rules. The most useful rule is required reviewers — a job targeting that environment pauses until a human approves it.
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- run: ./deploy.sh
With production configured to require approval and to hold the real deploy key, even a malicious push to main cannot deploy without a human clicking approve. That single setting prevents a surprising number of incidents.
OIDC: stop storing cloud keys
Long-lived AWS access keys in repository secrets are a leak waiting to happen. GitHub Actions can instead exchange a short-lived OIDC token with your cloud provider for temporary credentials. No static key ever exists.
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-deploy
aws-region: us-east-1
- run: aws s3 sync ./dist s3://my-bucket
On the AWS side you create an IAM role with a trust policy that only accepts tokens from your repo and branch. The result is least privilege and zero static credentials in the repo. Google Cloud and Azure offer the equivalent — Workload Identity Federation and federated credentials respectively.
Avoid leaking secrets to logs
GitHub masks known secret values in logs, but it cannot mask transformed versions. Common foot-guns include:
- Base64-encoding a secret and then printing it.
- Concatenating a secret with other text and echoing the result.
- Setting
set -xin a script that uses the secret on a command line. - Uploading a build artifact that includes a config file with the secret embedded.
A simple discipline helps. Treat secrets like radioactive material — pass them only into the one tool that needs them, never into a log statement, never into a build artifact.
Forks and pull requests
Secrets are not exposed to workflows triggered by pull requests from forks. That is a deliberate, important safety net — otherwise a stranger could open a PR that prints secrets.AWS_SECRET_ACCESS_KEY. If you need a workflow that requires secrets on PRs, use pull_request_target carefully, with a separate job that only runs after a maintainer label, or move to a workflow that runs after merge.
Rotation and auditing
Rotate secrets on a schedule, not after an incident. A token you have not rotated in two years is more likely to have leaked than a token you rotated last month. GitHub’s audit log records every time a secret is created, updated, or deleted; review it occasionally for entries you do not recognize.
gh secret list --repo my-org/my-repo
gh secret set NPM_TOKEN --repo my-org/my-repo
The gh CLI makes rotation scriptable, which is the only way rotation actually happens.
A short checklist
Use the narrowest scope. Pass secrets through env:, never inline. Require reviewers on production environments. Prefer OIDC over static cloud keys. Rotate on a calendar. Watch the audit log. Do those six things and most of the common GitHub Actions secret accidents simply cannot happen to you.
Related articles
- DevOps CI/CD Pipeline Design Fundamentals
How to design a CI/CD pipeline that stays fast, reliable, and reversible: stages, caching, parallelism, environments, and rollback strategies that scale with the team.
- CI/CD CI/CD Secrets Management Best Practices
Keep API keys, tokens, and database credentials safe in CI/CD with rotation, scoping, secret managers, and OIDC-based authentication.
- CI/CD GitHub Actions Reusable Workflows Tutorial
Stop copy-pasting CI YAML across repos. Learn how to build reusable GitHub Actions workflows with inputs, secrets, outputs, and per-environment overrides.
- Kubernetes Kubernetes Secrets: Best Practices for Production
Practical patterns for managing Kubernetes Secrets safely: encryption at rest, external secret stores, RBAC scoping, rotation, and avoiding common leaks.