Safeguard
Security Guides•

How do you inventory every secret your CI uses?

List repository, environment, organization, and Dependabot secrets with the GitHub CLI, then record owner, scope, and rotation date. A step by step method.

Safeguard Security Team
4 min read

To inventory CI secrets on GitHub, run the CLI's secret list command for each scope: repository, each environment, the organization, and the Dependabot and Codespaces stores. It returns names, visibility, and updated time, not values. Then add the missing columns yourself: owner, what it unlocks, and when it was last rotated.

Why inventory first

You cannot rotate what you cannot find. After an incident, the first question from responders is who had access, when the secret was used, and when it was last rotated. OWASP's secrets guidance lists exactly these as the information you need for investigation. An inventory built before the incident answers them in minutes.

What the command shows

The GitHub CLI manual lists the flags for the list command: one for the application store (actions, agents, codespaces, or dependabot), one for an environment, one for an organization, one for your user, and a repository selector. The JSON output fields documented are name, numSelectedRepos, selectedReposURL, updatedAt, and visibility. There is no field for the value.

gh secret list --repo OWNER/REPO
gh secret list --repo OWNER/REPO --env production
gh secret list --org OWNER
gh secret list --repo OWNER/REPO --app dependabot

Run these across every repository you own. A short loop over the repository list gets you a table in a few minutes.

Build the register

ColumnSource
Name and scopeThe list output
Last updatedupdatedAt from the output
VisibilityOutput; for organization secrets, which repositories can use it
What it unlocksAsk the owning team; check workflow files that reference it
OwnerA named person or team
Replace with OIDC?Decide per secret
Next rotation dueYou set this

Treat the register as sensitive. It maps your attack surface even though it holds no values.

Steps

  1. List repositories, including archived ones. Old repositories keep secrets alive.
  2. Run the list command for each scope and merge the output into one sheet.
  3. Search workflow files for references to each name, and note secrets that are defined but never used.
  4. Mark candidates for deletion. GitHub's guidance says to review registered secrets regularly and remove unneeded ones.
  5. Mark cloud keys as candidates to replace with OIDC, which lets you stop storing long lived credentials as secrets.
  6. Assign owners and set rotation dates.
  7. Re-run monthly and diff against the last run. New names and stale update dates are your signals.

Gaps to check

The CLI covers GitHub. Your pipeline may also hold credentials in a vault, a container registry, a package registry, or another CI tool. Add those sources to the register by hand. Do not forget Jenkins credential stores, GitLab variables, and any scripts on build servers.

Try it yourself

Click through it at your own pace, or open it full screen. Notice how a recurring check surfaces changes over time, which is the same habit that keeps an inventory from going stale.

Quick check

Can the list command reveal a secret value?

No. The documented fields are metadata only. Values cannot be read back from the settings page either.

How often should I refresh the inventory?

Monthly is a reasonable start, and again after any departure or incident. Adjust to how often your team creates secrets.

Safeguard asset discovery can help you find the repositories and pipelines that belong in this register, and compliance and evidence automation keeps the results as dated evidence. A free scan is at gold.safeguard.sh/scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.