Verifying signatures in air-gapped environments
Use Cosign to verify container signatures and attestations without outbound network access
For the complete documentation index, see llms.txt.
Octo STS is a GitHub App that exchanges OIDC tokens from your workloads for short-lived GitHub tokens, so your automation doesn’t need personal access tokens (PATs). This page shows you how to install Octo STS, write trust policies, exchange tokens, and fix failed exchanges. For background on why Octo STS exists, read Octo STS: Short-lived GitHub tokens without PATs in Supply Chain Security 101.
Octo STS issues tokens according to trust policies that you keep in your repositories:

Tokens expire after one hour and can’t be refreshed. When a token expires, exchange a new OIDC token for a new GitHub token.
Octo STS requests a broad set of permissions so that it can support many use cases, but the tokens it issues carry only the permissions that your trust policies grant. The app itself needs contents: read so that it can read your trust policies. Until you create a trust policy, Octo STS can’t issue any tokens.
The hosted service at octo-sts.dev is free to use. Octo STS is open source, so you can also host it yourself; the Octo STS repository has deployment instructions.
When Octo STS needs to add or remove GitHub permissions, the maintainers open an issue in the Octo STS repository that explains the change, and GitHub asks you to approve the updated permissions for your installation. These updates happen quarterly, except for critical changes.
Trust policies are YAML files at .github/chainguard/{name}.sts.yaml in your repository. Octo STS typically reads them from the default branch. A repository can have several policies, each with its own identity requirements and permissions:
.github/chainguard/renovate.sts.yaml.github/chainguard/deploy.sts.yaml.github/chainguard/ci.sts.yamlWhen your workload exchanges a token, it names the policy to use with the identity parameter.
To change a policy’s permissions, edit the file, then commit and push the change. New permissions apply to every exchange after that. Tokens that Octo STS already issued keep their original permissions until they expire.
Prefer exact subject matching:
subject: repo:org@<owner-id>/repo@<repo-id>:ref:refs/heads/mainUse a pattern only when you need the flexibility:
subject_pattern: "repo:org@<owner-id>/repo@<repo-id>:ref:refs/heads/.*"An exact match makes it harder to grant broader access than you intended.
Note: These subjects use GitHub’s immutable format, which embeds the numeric owner ID and repository ID in the
subclaim (for example,repo:org@123456/repo@654321:ref:refs/heads/main). This format is the default for repositories created after July 15, 2026, and an opt-in for older repositories. Match the exact subject your repository’s token carries. For how to find the IDs, refer to Finding your repository’s numeric identifiers.
To issue one token that works across several repositories, use an organization trust policy with a repositories field:
issuer: https://token.actions.githubusercontent.com
subject: repo:org@<owner-id>/automation-repo@<repo-id>:ref:refs/heads/main
permissions:
contents: read
repositories:
- org/repo-one
- org/repo-two
- org/repo-threeThe resulting token can access every listed repository.
Whatever a policy grants, GitHub still enforces branch protection. A token with contents: write must still meet requirements such as pull request reviews and status checks.
Octo STS works with any system that can obtain an OIDC token, such as Jenkins, GitLab CI, or CircleCI, and make an HTTP request to exchange it. The system needs an OIDC identity provider that Octo STS can validate.
For example, Terraform can exchange a token through its external data source:
data "external" "github_token" {
program = ["bash", "-c", <<-EOT
OIDC_TOKEN=$(get_oidc_token)
RESPONSE=$(curl -s -H "Authorization: Bearer $OIDC_TOKEN" \
"https://octo-sts.dev/sts/exchange?scope=org/repo&identity=terraform")
echo $RESPONSE | jq '{token: .access_token}'
EOT
]
}
provider "github" {
token = data.external.github_token.result.token
}You can use PATs and Octo STS side by side during a migration, which lets you move one workload at a time and roll back if you need to.
If a token exchange fails, check these common causes:
.github/chainguard/{identity}.sts.yaml.For a worked example, watch Updating container images with Renovate (and no PATs!).
Last updated: 2026-10-02 13:51