Audit GitHub Actions Variables with gh variable list
You will list GitHub Actions variables at repository, environment and organisation scope, then turn the result into a small JSON check suitable for a script. The examples use GitHub CLI gh version 2.87.3, installed here from package gh. Allow about ten minutes. You need a shell, an authenticated GitHub CLI session, and permission to read the variables for the selected repository or organisation.
The route
Jump straight to the step you need, or tick off Done means at the end.
This command only reads configuration. It does not create, change or delete a variable, and it does not need elevated Linux privileges. Values can still be sensitive in practice, so avoid pasting unfiltered output into tickets or logs.
1. Check the installed command
Confirm that the command is present and inspect the options on this machine:
$ gh --version
gh version 2.87.3 (2026-02-23)
$ gh variable list --help
The command has the alias gh variable ls. The repository is the default scope. The other scopes are selected with --env for a deployment environment or --org for an organisation. Keep the scope visible in scripts: a successful repository query does not prove that an environment or organisation variable is readable.
Checkpoint: if gh variable list --help fails, stop here and fix the CLI installation or your PATH before debugging GitHub permissions.
2. List variables for a repository
Run the repository-level query, replacing both placeholders with a repository you are allowed to inspect:
$ gh variable list --repo OWNER/REPOSITORY
NAME VALUE UPDATED
APP_MODE production 2026-09-20T12:34:56Z
The plain output is intended for a person reading a terminal. The exact rows depend on the repository and can change between runs. The command returns a non-zero status if GitHub refuses the request. For example, this can happen when the token lacks repository variable read permission, even though the repository itself is public.
Do not mistake an empty list for a failed query. An empty result can mean that the request succeeded and the selected scope has no variables. Check the command's exit status immediately if a script needs to distinguish an empty result from an API failure:
if gh variable list --repo OWNER/REPOSITORY; then
printf '%s\n' 'Variable query completed'
else
status=$?
printf 'Variable query failed with status %s\n' "$status" >&2
exit "$status"
fi
3. Query an environment or organisation
Use the environment name with the repository selector when the variables belong to a deployment environment:
$ gh variable list --repo OWNER/REPOSITORY --env staging
For organisation-level variables, use the organisation name instead:
$ gh variable list --org ORGANISATION
These options select different GitHub API resources. Do not combine --env and --org to try to search everything at once. Run separate, clearly labelled queries if you need an audit across scopes. The --repo option accepts [HOST/]OWNER/REPO, so an Enterprise Server target can include its host.
Checkpoint: write down the scope beside any captured result, for example repository:OWNER/REPOSITORY or environment:staging. A variable name by itself does not identify its scope.
4. Select fields for a repeatable check
Use --json when another tool needs structured data. The installed command advertises these fields: createdAt, name, numSelectedRepos, selectedReposURL, updatedAt, value and visibility.
$ gh variable list --repo OWNER/REPOSITORY --json name,updatedAt
[{"name":"APP_MODE","updatedAt":"2026-09-20T12:34:56Z"}]
Use the smallest field set that answers the question. This example deliberately leaves out value, which reduces the chance of exposing configuration in a captured log:
$ gh variable list --repo OWNER/REPOSITORY --json name,updatedAt --jq '.[] | [.name, .updatedAt] | @tsv'
APP_MODE\t2026-09-20T12:34:56Z
The --jq option filters the JSON returned by --json; it is not a replacement for the field list. GitHub CLI includes the jq formatter, so a separate jq installation is not required for this option. If you prefer Go templates, use --template instead:
$ gh variable list --repo OWNER/REPOSITORY --json name,visibility --template '{{range .}}{{.name}} ({{.visibility}}){{"\n"}}{{end}}'
APP_MODE (private)
To see the fields without fetching a list, run gh variable list --json with no field argument. The help output documents the available names, and the command still needs a valid scope and permission when it makes the request.
5. Handle the common failures
An HTTP 401 or 403 response normally points to authentication or permission rather than a malformed variable name. Check the current account and host with gh auth status, then ask for the repository or organisation variable read permission required by your token. Re-authentication is an account change, so do not run gh auth login on a shared machine unless you have checked which account and host it will affect.
For an Enterprise Server repository, include the host in --repo or set the intended GitHub host explicitly in your CLI configuration. A variable may also be absent because you queried the wrong scope, environment spelling or organisation. Repeat the query with the scope written beside it before treating absence as evidence that the variable does not exist.
There is no undo command needed for this guide because every example is read-only. If you copied a value into a terminal recording or log by mistake, remove that recording according to your local retention policy and consider rotating the value through the normal owner-approved process. Do not use gh variable list as a secret-auditing command: GitHub Actions secrets are a separate resource.
Done means
- You identified the installed
ghversion and confirmed the command syntax. - You queried the intended repository, environment or organisation scope.
- You checked the exit status and can distinguish an empty result from a failed request.
- You used
--jsonwith only the fields your check needs, avoiding values where possible. - You recorded the scope with the result and did not change GitHub configuration.