
Rotate GitHub Actions Secrets: Precedence Can Leave Old Values Active

To rotate a GitHub Actions credential, map the secret each affected job uses, create a replacement credential, update the effective secret scope, verify a fresh run, and then revoke the old credential. GitHub’s secrets reference gives environment secrets precedence over repository secrets with the same name, and repository secrets precedence over organization secrets. An older environment value can therefore remain active after you replace a shared organization value.
Keep the old and new credentials valid during verification if the issuing service allows overlap. That gives you a way to restore the previous value at the affected scope if the replacement fails. If the issuer permits only one active credential, plan a controlled cutover and expect a possible interruption.
Map the secret each job can receive
Start with the workflows that use the credential. Record each secret name, repository, job environment, organization access policy, and external service account. Search workflow files and reusable workflow calls for the name, then identify the trigger and environment used by each affected job. Jobs in the same repository can receive different values when only one references an environment.
GitHub’s secret management instructions give separate commands for each scope: gh secret list for the current repository, gh secret list --env ENV_NAME for an environment, and gh secret list --org ORG_NAME for an organization. Check every environment used by the jobs and review which repositories may access the organization secret. The lists show names, not secret values, so use them to find duplicate names and possible overrides.
Consider a conditional example: DEPLOY_TOKEN exists at organization, repository, and environment scopes. A deployment job referencing that environment receives its environment value; a job without that environment can receive the repository value. If another repository has access to the organization secret and has no local copy, its job can receive the organization value. Map these as separate rotation targets, even if someone originally stored the same credential in each place.
Create the replacement and update the intended scope
Issue a new credential with the permissions required by the workflow. Where the issuer supports overlapping credentials, retain the old one until the replacement has passed verification. Record an identifier for each credential in a secure change record so you can distinguish their use without recording either secret value.
Update the scope the job resolves: gh secret set SECRET_NAME for the repository, gh secret set --env ENV_NAME SECRET_NAME for an environment, or gh secret set --org ORG_NAME SECRET_NAME for an organization. The CLI can prompt for the value or read it from standard input. Avoid putting the value directly in a command argument, where it could be exposed through shell history or process inspection.
Review organization secret access before changing a shared value. An organization update may affect several repositories but will not replace a repository or environment override with the same name. If a rotation requires changes at multiple scopes, update each intended copy while both credentials remain valid. Retain the previous value in an approved credential store for rollback; a GitHub secret listing will not retrieve it.
Verify a fresh run without exposing the value
Start a new run using the trigger and job environment that matter for the affected workflow. GitHub reads organization and repository secrets when a run is queued, but reads environment secrets when the referencing job starts. A run queued before an update may still carry an old repository or organization value; check the run’s timing before treating it as verification.
Have the job perform a safe operation that requires the credential, and inspect the result without printing the secret. A successful run during an overlap proves that authentication worked, but does not by itself show which credential worked. If the issuing service records credential identifiers or authentication events, match the new identifier to the fresh run. Where that evidence is unavailable, verify each consumer path and treat revocation as a closely monitored part of the cutover.
Test under the same conditions as the real job. Actions secrets are withheld from workflows triggered by forked repositories, apart from GITHUB_TOKEN; they are unavailable to workflows triggered by Dependabot events and are not automatically passed to reusable workflows. A test that changes the trigger, skips a reusable workflow, or omits the deployment environment can miss the value you meant to replace.
Revoke the old credential and remove stale copies
Once the affected paths have worked with the replacement, revoke the old credential at its issuer and watch the next normal runs for authentication failures. Revocation ends the usefulness of an overlooked old copy outside the workflow you tested. If verification fails while the old credential remains valid, restore its value at the affected GitHub scope, investigate the mapping, and delay revocation.
Check duplicate secret names again before deleting an override. Removing an environment secret can expose a repository value; removing a repository secret can expose an organization value. Confirm that the value and access policy underneath are the ones you intend the job to use. Otherwise, cleanup can silently switch the job back to an older credential.
Keep a change record containing the secret name and scope, affected repositories and environments, the replacement credential identifier, change time, verification run IDs, and revocation time. Store outcomes and identifiers, never secret values. That record lets another operator tell whether the credential was actually retired or merely replaced at one GitHub scope.
Use short-lived identity where the provider supports it
For supported cloud services, GitHub’s OpenID Connect guidance describes how a workflow can obtain a short-lived cloud access token without storing a long-lived cloud credential as a GitHub secret. Configure the provider’s trust conditions for the intended workflow identity, verify the new authentication path, and then revoke the former cloud credential. Remove its GitHub secret copies only after checking which values their deletion would expose.
Also read:
Related articles


Patreon API v1 Is Off—Old Membership Webhooks Need a Rewrite

Passkeys vs Passwords: Phishing Resistance Wins, but Recovery Still Matters

EU Digital Omnibus Stalls Again—Current GDPR Rules Still Apply

Backblaze B2 vs Wasabi: Cheap Storage Splits at Restore Time

Cursor vs GitHub Copilot: A $10 Gap Hides a Task-Type Split
Subscribe to our newsletter
Get the latest Web3, AI, and crypto news delivered straight to your inbox.