ENTIRE_TOKEN Security and Validation Fixes · Entire

Here are the open comments on PR #1321. They come from two reviewers — toothbrush (human) and Copilot (bot).

toothbrush — doc-comment wording suggestions (3)

All // suggestion edits to comments in cmd/git-remote-entire/main.go:

These are trivial accept-the-suggestion edits to make the doc comments accurate.

Copilot — substantive findings (3 distinct issues)

  1. env_token.go:57 — loose aud URL validation. CoreURLFromEnvToken accepts any http(s) URL with a non-empty host, including userinfo/query/fragment. An aud like https://core.example.com?x=1 would flow into repocreds as coreURL + "/oauth/token", producing an invalid endpoint. Suggests rejecting userinfo/query/fragment and returning a canonicalized scheme/host/path URL.

  2. main.go:148 — empty ENTIRE_TOKEN silently falls back. When ENTIRE_TOKEN="" (or whitespace), it's treated as unset and falls back to contexts/keyring. This contradicts the stated design that a mis-set token should fail loudly, never fall back.

  3. env_token.go:66–76 — credential leak in error messages (6 comments). Error strings use u.String(), which includes userinfo if present. Should use u.Redacted() to avoid leaking passwords to stderr/logs.


The Copilot findings 1 and 3 are related — both about hardening the aud URL parsing. Want me to address these? My suggested plan:

Should I go ahead and implement all of these, or do you want to review/scope first?

ENTIRE_TOKEN Explanation

It's a login (or sa-session) JWT — a subject token, not an access token

ENTIRE_TOKEN holds a signed JWT that identifies a principal, used as the subject token in an OAuth token exchange. It is not the token that actually authenticates git operations — it's the credential you trade in to mint those.

What's inside it

tokens.ParseClaims reads these claims — without verifying the signature (that's the issuing server's job; the CLI only reads claims for routing):

Claim Use
iss issuing core (may be a regional core)
sub principal subject
aud home-region core URL — what we route the exchange to
handle display name of the principal
exp/iat/nbf lifetime

Note the deliberate choice: the code keys on aud, not iss because iss may be a regional core that can't mint the cross-region exchange, whereas aud is the home-region URL that STS routing expects.

Why this PR has a security gate around it

Because the exchange host (coreURL) is derived from the token's unverified aud, a forged token could otherwise redirect your credential to an attacker's host. That's why resolveEnvTokenCreds anchors trust to the clone URL's host you typed — fetching /.well-known/entire-cluster.json over TLS and checking the derived core is one the cluster actually advertises (coreTrusted) before ever POSTing the token to it.


TL;DR: ENTIRE_TOKEN is a signed login/service-account identity JWT. The CLI reads its aud to find the home-region core, verifies that core is trusted for the cluster you're cloning, then exchanges the token (RFC 8693) for short-lived, per-repo access tokens that do the real git auth. The env-var path lets CI inject that identity JWT directly.