For AI agents: A markdown version of this page is available at https://docs.datadoghq.com/security/code_security/iac_security/iac_rules/cicd-github-secrets-outside-env.md.
A documentation index is available at /llms.txt.
Secrets referenced in GitHub Actions jobs should be scoped to a dedicated environment to limit their availability and reduce the blast radius if credentials are exposed. This rule inspects workflow job definitions and flags jobs that reference the secrets context in fenced expressions but do not define the environment property. It looks for secrets.<NAME> usages in expressions and excludes secrets.GITHUB_TOKEN, which is always available. Any job without an environment that accesses secrets.* will be reported.
Remediate by adding an environment to the job and moving sensitive values to environment-scoped secrets with appropriate approvals, or confirm that repository/org-level secrets are intentionally used.
Compliant Code Examples
name:Secrets in Environmenton:pushjobs:deploy:runs-on:ubuntu-latest# Proper: job has environment defined, so secrets are scopedenvironment:productionenv:API_KEY:${{ secrets.API_KEY }}if:${{ secrets.DEPLOY_TOKEN != '' }}steps:# Proper: secrets used within environment- name:Deploy with secretsrun:| echo "Deploying..."
curl -H "Authorization: Bearer ${{ secrets.DEPLOY_TOKEN }}" https://api.example.com/deploy# Proper: step-level if with secret within environment- name:Check production keyif:${{ secrets.PRODUCTION_KEY != '' }}run:echo "Has production key"# Proper: step env with secret within environment- name:Step with env secretenv:DB_PASSWORD:${{ secrets.DB_PASSWORD }}run:echo "Configured database"# Proper: step with block with secret within environment- name:Action with secretuses:some/action@v1with:token:${{ secrets.SERVICE_TOKEN }}api_key:${{ secrets.API_KEY }}staging:runs-on:ubuntu-latest# Proper: another job with environmentenvironment:stagingenv:STAGING_KEY:${{ secrets.STAGING_KEY }}if:${{ secrets.STAGING_TOKEN != '' }}steps:- run:echo "Deploying to staging"# Proper: reusable workflow calls are skippedcall-workflow:uses:./.github/workflows/deploy.ymlsecrets:token:${{ secrets.DEPLOY_TOKEN }}# Proper: job without secrets doesn't trigger the rulebuild:runs-on:ubuntu-lateststeps:- uses:actions/checkout@v4- run:npm build# Proper: using GITHUB_TOKEN is allowed (explicitly excluded in the rule)test:runs-on:ubuntu-lateststeps:- name:Checkout with GITHUB_TOKENrun:| curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
https://api.github.com/repos/${{ github.repository }}
Non-Compliant Code Examples
name:Secrets Outside Environmenton:pushjobs:deploy:runs-on:ubuntu-latest# Secret used in job-level env without environmentenv:API_KEY:${{ secrets.API_KEY }}# Secret used in job-level if without environmentif:${{ secrets.DEPLOY_TOKEN != '' }}steps:# Secret used in step run block without environment- name:Deploy with secretsrun:| echo "Deploying..."
curl -H "Authorization: Bearer ${{ secrets.DEPLOY_TOKEN }}" https://api.example.com/deploy# Secret used in step-level if without environment- name:Check secretif:${{ secrets.PRODUCTION_KEY != '' }}run:echo "Has production key"# Secret used in step env block without environment- name:Step with env secretenv:DB_PASSWORD:${{ secrets.DB_PASSWORD }}run:echo "Configured database"# Secret used in step with block without environment- name:Action with secretuses:some/action@v1with:token:${{ secrets.GITHUB_TOKEN }}api_key:${{ secrets.SERVICE_KEY }}another-job:runs-on:ubuntu-latest# Another job-level env without environmentenv:TOKEN:${{ secrets.SERVICE_TOKEN }}# Another job-level if without environmentif:${{ secrets.ADMIN_KEY != '' }}steps:- run:echo "Running"
1
2
rulesets:- CICD / GitHub # Rules to enforce / GitHub.
Request a personalized demo
Get Started with Datadog
Ask AI
AI-generated responses may be inaccurate. Verify important info.