Safeguard
Security Guides•

A starter workflow asks for a secret: what do you store, and where?

When a CI template references a secret, create a narrow credential, store it at the right scope, and confirm the job needs it. A short decision guide.

Safeguard Security Team
3 min read

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

ScopeGood forWatch out for
Repository secretOne repo, low risk, such as a test service keyAny writer can use it
Environment secretDeploy and publish jobsNeeds the job to name the environment
Organization secretShared credentials across selected reposWider 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

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.