Home / Alt manpages / gh-secret(1)

  • gh-secret(1)
  • User command
  • linux

Set, Check and Remove GitHub Secrets with gh secret

A deploy token belongs in a secret, not in a dotenv file that ends up in a commit. With gh secret you can create or update a GitHub secret, confirm its name exists without printing the value, and remove it when it is no longer needed. The examples use GitHub CLI 2.87.3, installed here as the gh package, and take about 10 minutes if you already have a working gh auth session and repository access.

Before you start

You need GitHub CLI installed and authenticated, plus permission to manage secrets at the selected scope. No command in this guide needs sudo. The current repository is the default target. To make the target explicit, use --repo OWNER/REPO or its short form -R OWNER/REPO on the command that supports it.

Warning

Secret values are sensitive. Do not put a real value directly in a command, commit a dotenv file, or paste a token into a terminal recording. The CLI encrypts values locally before sending them to GitHub, but your shell history and surrounding tooling can still expose a value passed as an argument.

$ gh --version
gh version 2.87.3 (2026-02-23)

$ gh auth status
Authenticated to github.com

If the second command reports no usable account, stop and authenticate with gh auth login before changing anything.

1. Choose the secret scope

gh secret manages repository secrets by default. The same command group can address an Actions environment with --env, an organisation with --org, or your user-level Codespaces secrets with --user. The --app option selects Actions, Codespaces, or Dependabot where that distinction applies.

Select a repository explicitly when you are running outside a checked-out copy, or whenever a similarly named repository could cause confusion:

$ gh secret list --repo EXAMPLE_ORG/EXAMPLE_REPO

Checkpoint

You should see a table of secret names and metadata, with no values. An empty list can be a correct result, but it can also mean you selected the wrong repository, account, environment, or application.

2. Create or update a repository secret

Use standard input for a value that is not already safely held by your shell environment. This keeps the value off the command line:

$ gh secret set DEPLOY_TOKEN --repo EXAMPLE_ORG/EXAMPLE_REPO

✓ Paste your secret: ********

The command creates the secret if the name is new, or updates it if the name already exists. The value is not recoverable through gh secret list. If you lose it, generate or retrieve a replacement from the system that issued it.

For automation, read the value from an environment variable provisioned by your secret manager. Quote the expansion and avoid enabling shell tracing around the command:

set +x
gh secret set DEPLOY_TOKEN --repo EXAMPLE_ORG/EXAMPLE_REPO --body "$DEPLOY_TOKEN_VALUE"

The command normally prints a short success message such as ✓ Set secret DEPLOY_TOKEN.

Warning

If the value is visible in an error, terminal capture, or process-monitoring system, treat it as compromised and rotate it.

3. Set an environment or application secret

An environment secret is still attached to a repository, but it is available to Actions runs for the named deployment environment. Keep the scope in the command and check the name before setting it:

$ gh secret list --repo EXAMPLE_ORG/EXAMPLE_REPO --env production
$ gh secret set DEPLOY_TOKEN --repo EXAMPLE_ORG/EXAMPLE_REPO --env production

When the same name exists at repository and environment level, your workflow's context determines which value is used. Do not assume that updating one replaces the other.

For a repository secret used by Dependabot rather than Actions, select the application explicitly:

$ gh secret set DEPENDABOT_TOKEN --repo EXAMPLE_ORG/EXAMPLE_REPO --app dependabot

Organisation secrets use --org ORG. Their default visibility is private. Use --visibility selected with --repos repo-one,repo-two when only named repositories should have access.

Warning

Treat --visibility all as a security-sensitive change, because it makes the secret available to all repositories in that organisation.

4. Verify metadata without revealing the value

List the relevant scope and request only the fields useful for an audit. Secret values are not part of the list response:

$ gh secret list --repo EXAMPLE_ORG/EXAMPLE_REPO --json name,updatedAt,visibility
[{"name":"DEPLOY_TOKEN","updatedAt":"2026-09-24T09:30:00Z","visibility":"private"}]

The timestamp in this example is illustrative, so use the value your repository returns. You can filter the JSON with --jq or format it with --template. Remember that metadata can still reveal deployment names or organisational structure.

5. Remove a secret only when you mean to

Before removing a value, search the workflow and deployment configuration for its name, then confirm the exact scope:

$ gh secret list --repo EXAMPLE_ORG/EXAMPLE_REPO --env production
$ gh secret delete DEPLOY_TOKEN --repo EXAMPLE_ORG/EXAMPLE_REPO --env production
✓ Deleted secret DEPLOY_TOKEN

Warning

Deletion is irreversible from the CLI, and there is no undo command.

Recovery

If a deletion breaks a workflow, restore the secret by setting a newly issued value, not by copying one from shell history or logs. Organisation and user secrets need the same scope flags to delete:

$ gh secret delete OLD_TOKEN --org EXAMPLE_ORG
$ gh secret delete CODESPACE_TOKEN --user

Common traps

  • Wrong repository: gh secret uses the current repository unless --repo says otherwise. Print the target before a change if you are switching between checkouts.
  • Wrong level: --env, --org, and --user select different stores. A successful command at one level does not update a same-named secret at another level.
  • Missing value input: without --body, gh secret set reads from standard input. That is useful interactively, but a redirected file must be protected and must not be committed.
  • Expecting to read a secret back: listing returns names and metadata, not plaintext. Plan rotation and recovery through the original secret issuer.

Done means

  • Scope chosen. The intended repository, environment, organisation, or user scope was selected explicitly.
  • Value kept private. The secret was set without exposing its value in command history or logs.
  • Metadata only. gh secret list shows the expected name and metadata, without a plaintext value.
  • Deletion safe. Any deletion was confirmed against the exact scope, with a replacement or rotation path available.