Use a separate registry credential per client, store it as an encrypted CI secret rather than in the repo, prefer short-lived OIDC tokens where your registry supports them, and revoke agency-held tokens at handover. One shared token across clients turns a single leak into many incidents.
Why shared tokens hurt
Agencies often keep one registry account and one token that every project uses. It is easy. It also means that a laptop theft, a leaked CI log or a departing contractor puts every client's private packages at risk, and nobody can tell which project used the token.
What GitHub documents for Dependabot
GitHub's documentation on private registries shows the pattern in one place, even if you use other tools.
- Credentials are stored as encrypted secrets. They are encrypted before reaching GitHub and stay encrypted until used.
- The configuration file refers to a secret by name, so the raw value never appears in the repository.
- Secret names use letters, numbers and underscores, and cannot start with a number or GITHUB_.
- Repository secrets need ownership or admin access. Organization secrets can be limited to selected repositories.
- GitHub Packages and its container registry need no stored token for Dependabot, which authenticates with its own token once the repository is granted read access.
- Third-party registries still need an entry in the configuration, and organization-level registries support token, username and password, and OIDC authentication.
- With OIDC, supported providers issue short-lived credentials, so you do not store long-lived secrets.
A workable setup
- One organization or account per client, or at least one scoped credential per client.
- Read-only tokens for installs. Publishing tokens only in the release job.
- Secrets in the CI platform's secret store. Never in package manager config files committed to the repo.
- Short lifetimes. Prefer OIDC. If you must use long-lived tokens, set an expiry and a calendar reminder.
- A secrets list in the handover pack, as in what to hand over with a client codebase.
Watch the leaks
Secrets show up in places teams forget: CI logs, Docker build layers, npmrc files in a repository, and screenshots in tickets. GitHub's Actions guidance notes that automatic log redaction is not guaranteed, because there are many ways a secret value can be transformed. If a secret reaches a log, delete the log and rotate the secret.
At handover
Create new credentials in the client's account, update the pipeline, test a build, then revoke yours. Order matters. Revoking first breaks the client's first deploy and starts the relationship badly.
Quick check
Is a private registry needed for every client?
No. Many sites use only public packages. Use a private registry when the client owns internal packages or wants an approved mirror.
Is a read-only token safe to commit?
No. Read-only still exposes private packages. Keep it in a secret store.
Sources
- GitHub Docs: Configuring access to private registries for Dependabot
- GitHub Docs: Security hardening for GitHub Actions
Last reviewed: 19 October 2026.