Create the narrowest credential that does the job, store it as a secret at the smallest scope that works, and use environment secrets with required reviewers for anything that publishes or deploys. Then read the logs after a test run. Redaction is helpful, but it is not a guarantee.
Why templates mention secrets
GitHub's template guide notes that some templates use secrets, for example an npm token. If one does, you store a value under that secret name in your repository. That is easy to do and easy to overdo. The question is not just where to put it, but whether to create it.
Step 1: do you need the secret at all?
If the job builds and tests, it probably does not need a publish token. Delete the step and the reference. If it deploys to a cloud account, ask whether short lived federated credentials are available instead. GitHub describes OpenID Connect as a way to authenticate to a cloud provider without storing long lived credentials as secrets. See replacing long lived cloud secrets with OIDC.
Step 2: make the credential narrow
GitHub notes that anyone with write access to a repository can read all secrets configured there. So the credential should be least privilege: scoped to one package or one environment, with the shortest practical lifetime. A token that can publish every package in your account is a bad fit for a template you did not write.
Step 3: choose the scope
| Scope | Good for | Watch out for |
|---|---|---|
| Repository secret | One repo, low risk, such as a test service key | Any writer can use it |
| Environment secret | Deploy and publish jobs | Needs the job to name the environment |
| Organization secret | Shared credentials across selected repos | Wider blast radius, limit by repository |
GitHub says you can protect environment secrets with required reviewers, so a job cannot read them until a reviewer approves. For a publish or deploy template, that is a worthwhile gate.
Step 4: avoid structured secrets
GitHub's guidance is not to wrap a secret in JSON, XML or YAML, because log redaction relies on matching the exact secret value. Create one secret per sensitive value instead. If your workflow transforms a secret, for example by Base64 encoding it, register the new value as a secret too.
Step 5: test the logs
Run the workflow with a valid and an invalid input, then read the whole log. GitHub advises doing this because tools can send errors to standard output or standard error in ways you do not expect. If a secret does show up in a log, delete the log and rotate the secret.
Step 6: schedule a rotation
Review stored secrets now and then, remove the ones no job uses, and rotate the rest. A calendar entry is enough.
Quick check
Does GitHub always hide secrets in logs?
No. GitHub says automatic redaction is not guaranteed, because a value can be transformed in many ways before it is printed.
Should a template copied from the internet get my production token?
Not on first run. Test with a throwaway credential and a separate environment, then promote after you have read what the workflow does.
Sources
- Using workflow templates, GitHub Docs
- Secure use reference, GitHub Docs
- OpenID Connect in GitHub Actions, GitHub Docs
Last reviewed: 19 October 2026.