Skip to main content
GitHub Actions

GitHub Actions secrets: inject configuration without leaking it to logs

Give deployment secrets to one protected job and one step where possible; masking in logs is not a security boundary.

Thien Nguyen
By Thien Nguyen
Updated July 21, 2026 · 2 min read

A CI secret should be a narrowly granted capability, not ambient process state inherited by every job. Put production credentials behind a protected environment, inject them into the deployment step only, and never execute untrusted pull-request code in that context.

Keep the scope close to the use

deploy:
  environment: production
  permissions:
    contents: read
    id-token: write
  steps:
    - uses: actions/checkout@<pinned-sha>
    - name: Deploy
      env:
        DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
      run: ./scripts/deploy
ScopeGood fitRisk
Repository secretOne repository's automationAny permitted workflow can misuse it
Environment secretProduction deployRequires deliberate approval/configuration
Organisation secretShared serviceEasy to overexpose to repositories

DEPLOY_TOKEN is limited to the step rather than workflow-wide. That distinction matters when later steps run third-party actions or diagnostic shell commands.

Masking only hides recognised values in logs. It does not prevent a script from sending a secret to the network, encoding it, or writing it into an artifact.

Do not mix trusted and untrusted execution

Fork pull requests must not receive deploy secrets. pull_request_target runs with base-repository privileges, so checking out and executing the contributor's revision there can turn a documentation PR into credential theft. Test untrusted code with no secrets; deploy from a reviewed branch in a separate workflow or protected job.

Prefer short-lived identity

For cloud providers, GitHub's OIDC token can be exchanged for an expiring credential constrained by repository, branch, and environment. That removes a long-lived cloud key from GitHub entirely. Pin action versions to commit SHAs, use the minimum permissions, and make a deployment credential capable of only the one deployment operation it needs.

The safest secret is one that exists briefly, is usable in one place, and can do very little if it escapes.

References

Primary documentation and specifications checked when this article was last updated.

GitHub ActionsCI/CDSecurity

Related articles

All articles