How to Rotate GitHub Actions Credentials Safely
Replacing a GitHub Actions publishing credential is not complete when a repository secret has a new value. The workflow may reference a different secret, deployment environment, provider account, or target than you expect. A green job may also show only that a command completed, not that the intended site was published with the replacement credential.
Treat the change as a staged release operation. Inventory the old credential’s dependencies, create a replacement with the same intended scope, switch the workflow deliberately, verify the workflow and published site, then revoke the old credential. If the release result is uncertain, stop creating new publishing side effects until you reconcile it.
Inventory the old publishing path
Start with a credential dependency record. Do not begin by editing the secret field. Record:
- The credential’s provider and account or project
- Its intended permissions and deployment target
- The repository, organization, or environment where it is stored
- Every workflow and job that may reference it
- The exact secret name used by those workflows
- Branch, tag, event, and manual-trigger conditions
- The build output and publication destination
- The person responsible for validation and revocation
GitHub’s Actions secret-management documentation is the appropriate starting point for locating and managing repository secrets. GitHub also publishes security guidance for Actions workflows. These references do not, by themselves, establish how a particular static-site provider handles scopes, deployment acknowledgements, or secret selection. Those details belong in your provider-specific record.
Check the workflow files rather than relying on memory. Search for the secret name, environment assignments, reusable workflows, composite actions, and deployment steps. Also inspect any environment-specific configuration that could send a successful build to the wrong target.
This inventory separates three changes that are often confused: replacing a credential, changing the workflow that consumes it, and changing the deployment provider or target. If more than the credential is changing, treat those as separate release changes where possible. Otherwise, a failed publication will be difficult to diagnose.
Create the replacement with the same intended scope
Create the new credential at the provider before changing the workflow. Give it only the permissions required to publish the site. Do not broaden its access merely because the old credential had excessive permissions. A rotation is an opportunity to correct scope, but a scope change also creates a new variable in the release. Record it explicitly.
Keep the old credential available during a short, bounded transition window. This reduces the chance that a configuration mistake immediately turns into an outage. It also means the old credential remains usable for that period, so define who can end the overlap and when.
Never print the credential, place it in command output, or use it as a diagnostic value. Validate the configuration around it instead. For example, confirm that the expected secret name is referenced and that the publishing job receives a nonempty value without exposing the value itself. A presence check cannot prove that the credential is valid, correctly scoped, or used by the provider.
If the deployment provider supports GitHub Actions OIDC, investigate whether it can replace a stored long-lived publishing token. Vendor guidance on GitHub Actions secret management presents OIDC as an alternative in supported integrations, but provider compatibility and trust configuration must be checked separately. Do not assume that an OIDC design works for every static-site host.
Switch the workflow deliberately
Change the workflow reference in a small, reviewable update. If the secret name stays the same, the change may occur only in the repository or environment settings. If the name changes, update every known consumer and make the old reference easy to detect.
Run the narrowest controlled publication that exercises the real deployment path. A local Hugo build can confirm that content and generated output are valid, but it cannot confirm that GitHub Actions authenticated to the intended provider or that the expected public site changed. Conversely, a successful authentication check does not prove that the correct artifact was published.
Keep content and credential validation distinct. You can run deterministic Hugo checks before publishing to catch draft, stale-output, or unintended-content problems before the credential change is tested. That reduces the chance of confusing a content failure with an authentication or deployment failure.
Verify more than a green workflow
Define the verification contract before the test run. At minimum, seek separate evidence for three stages:
Workflow execution
Confirm that the intended workflow, commit or release identity, branch, and deployment job ran. Check that the job reached the provider-facing step and did not skip it because of a condition, environment rule, or earlier failure.
Provider acknowledgement
Use the deployment provider’s available record to determine whether it accepted the upload or deployment request. The exact signal varies by provider. A completed workflow step is not a substitute for provider confirmation when the provider exposes a separate deployment record.
Public deployment state
Inspect the expected public URL or other authoritative release signal. Check that the intended change is present, the target is the correct site, and the result is not merely a cached or preview response. If you rely on a release identifier, record which identifier connects the public result to the workflow run.
The strength of the conclusion depends on the signals you can actually observe. A workflow success with no provider record may establish that the job completed, but not that publication finished. A public change without a trustworthy release identity may show that the site changed, but not which credential or run caused it.
Revoke the old credential after verification
Revoke the old credential only after the replacement has passed the verification contract. Record the replacement timestamp, workflow run, provider acknowledgement, public-state evidence, and revocation timestamp. The old credential should remain active only for the bounded period needed to obtain that evidence, not as a permanent fallback.
Revoking first can reduce exposure time, but it turns an incorrect secret name, scope, or target into an immediate publishing outage. Keeping both credentials active indefinitely creates a different problem: nobody can tell which path remains usable, and the old credential may stay active after its purpose has ended.
After revocation, run a non-destructive check that confirms the old credential is no longer accepted if the provider offers a safe way to do so. Do not test by repeatedly attempting production publication. The aim is to verify revocation without creating unnecessary deployment effects.
Stop when the release outcome is unknown
A timeout, interrupted job, provider error, or lost acknowledgement does not necessarily mean that nothing was published. The build may have completed, an upload may have been accepted, or the public target may be changing while the workflow reports an error.
Mark the transition as unknown rather than immediately retrying or revoking both credentials. Preserve the workflow run, commit, generated artifact identity, provider response, timestamps, target URL, and affected release. Then handle an unknown publishing state before authorizing another production attempt.
During reconciliation, distinguish these outcomes:
- The replacement was rejected and the old path remains the known publishing route.
- The replacement was accepted and the intended release is public.
- The deployment completed, but its release identity is not yet confirmed.
- Neither credential’s result can be established.
Only the first two outcomes support a straightforward next action. The third requires evidence collection before retrying. The fourth may require provider support, a manual deployment decision, or a controlled rollback. Do not describe an unknown result as a clean failure merely because the workflow ended unsuccessfully.
A safe rotation ends with a decision record, not just a changed secret. The record should show what depended on the credential, what replacement was introduced, which signals verified the switch, when the old credential was revoked, and how any uncertainty was resolved. That turns a one-time settings change into a repeatable publishing control.