Problem
When two npm registries share the same hostname but use different URL paths, the proxy sends the wrong static token credential. The HandleRequest loop in npm_registry.go matches on host+port only and returns on the first match — it never compares the request URL path against the credential's registry path.
This is the static-token equivalent of #87 / #71, which were fixed for OIDC credentials via OIDCRegistry (longest path-prefix matching). The static credential fallback path was not updated.
Reproduction
dependabot.yml:
registries:
registry-a:
type: npm-registry
url: https://artifactory.example.com/artifactory/api/npm/team-a-npm
token: ${{secrets.TEAM_A_TOKEN}}
registry-b:
type: npm-registry
url: https://artifactory.example.com/artifactory/api/npm/team-b-npm
token: ${{secrets.TEAM_B_TOKEN}}
The proxy receives credentials in order: [registry-a, registry-b]. A request to https://artifactory.example.com/artifactory/api/npm/team-b-npm/@scope/pkg matches registry-a first (same host, same port) and sends TEAM_A_TOKEN → 403 from Artifactory because that token is scoped to team-a-npm only.
Proxy logs
proxy | [056] GET https://artifactory.example.com:443/artifactory/api/npm/team-b-npm/@scope%2Fpkg
proxy | [056] * authenticating npm registry request (host: artifactory.example.com, token auth)
proxy | [056] 403 https://artifactory.example.com:443/artifactory/api/npm/team-b-npm/@scope%2Fpkg
Root cause
npm_registry.go lines 80–105 — the static credential loop:
for _, cred := range h.credentials {
regURL, err := helpers.ParseURLLax(cred.registry)
// ...
if !npmRegistryHostMatches(host, reqHost) {
continue
}
// No path check — first host+port match wins
// ...
return req, nil
}
Suggested fix
Add path-prefix matching before applying the credential, consistent with OIDCRegistry.TryAuth:
regPath := strings.TrimSuffix(regURL.Path, "https://github.com/")
if regPath != "" && !strings.HasPrefix(req.URL.Path, regPath+"https://github.com/") && req.URL.Path != regPath {
continue
}
This ensures /team-a-npm credentials only apply to /team-a-npm/... requests.
Impact
Any user with multiple npm registries on the same host using static tokens (non-OIDC). Common with JFrog Artifactory, AWS CodeArtifact, and Azure DevOps where a single hostname serves multiple virtual repositories.
Related
Problem
When two npm registries share the same hostname but use different URL paths, the proxy sends the wrong static token credential. The
HandleRequestloop innpm_registry.gomatches on host+port only and returns on the first match — it never compares the request URL path against the credential's registry path.This is the static-token equivalent of #87 / #71, which were fixed for OIDC credentials via
OIDCRegistry(longest path-prefix matching). The static credential fallback path was not updated.Reproduction
dependabot.yml:The proxy receives credentials in order:
[registry-a, registry-b]. A request tohttps://artifactory.example.com/artifactory/api/npm/team-b-npm/@scope/pkgmatchesregistry-afirst (same host, same port) and sendsTEAM_A_TOKEN→ 403 from Artifactory because that token is scoped toteam-a-npmonly.Proxy logs
Root cause
npm_registry.golines 80–105 — the static credential loop:Suggested fix
Add path-prefix matching before applying the credential, consistent with
OIDCRegistry.TryAuth:This ensures
/team-a-npmcredentials only apply to/team-a-npm/...requests.Impact
Any user with multiple npm registries on the same host using static tokens (non-OIDC). Common with JFrog Artifactory, AWS CodeArtifact, and Azure DevOps where a single hostname serves multiple virtual repositories.
Related