Every CLI tool that needs to reach the internet from inside a corporate network eventually has to answer the same question: how does it authenticate to the proxy sitting in front of it? curl answered that question two different ways in 2026 that turned into CVEs. CVE-2026-6253 documents a case where curl follows a redirect that changes which proxy environment variable applies — say, from http_proxy to https_proxy — and credentials learned for the original proxy persist in per-transfer state, ending up sent to a completely unrelated proxy. CVE-2026-8927 is a sibling bug: reusing a curl handle across sequential requests while switching proxies via environment variables can fail to clear proxy authentication state between requests, leaking credentials meant for proxy A to proxy B. Both are documented on curl.se's own CVE pages. Neither is exotic — they happen in ordinary automation scripts that loop over multiple endpoints with different proxy configs. This piece walks through how CLI proxy authentication actually works, where it goes wrong, and what npm's decade-old .npmrc credential problem has in common with curl's redirect bug: both come down to treating proxy credentials as incidental configuration instead of secrets that need their own handling.
How does a CLI tool decide which proxy credentials to send where?
Most CLI tools resolve proxy configuration from environment variables — http_proxy, https_proxy, no_proxy, and their uppercase variants — checked at request time, with embedded user:pass@host:port syntax carrying credentials directly in the URL. curl's own documentation (everything.curl.dev) notes it deliberately only honors the lowercase http_proxy, not HTTP_PROXY, for exactly one historical reason: the "httpoxy" class of bug. In CGI-invoked environments, the CGI spec turns an incoming HTTP Proxy: header into an HTTP_PROXY environment variable, and any HTTP client that blindly trusted that variable would let a remote, unauthenticated attacker redirect a server's outbound traffic — and any credentials configured for the legitimate proxy along with it — to an attacker-controlled host. That single case-sensitivity choice is a reminder that proxy config resolution isn't cosmetic; it's an attack surface with a real CVE history behind it (the original httpoxy disclosure affected PHP, Python, Go, and several other language ecosystems simultaneously in 2016).
Why did curl's own redirect and connection-reuse handling leak proxy credentials?
Both 2026 curl CVEs share a root cause: proxy authentication state was scoped too broadly relative to how long it stayed valid. In CVE-2026-6253, a redirect response can cause curl to switch from an HTTP proxy to an HTTPS proxy mid-transfer, but credential state cached from resolving the first proxy's URL wasn't cleared before curl connected to the second, different proxy — so a script proxying only through an internal HTTP proxy could have those credentials forwarded to whatever proxy the HTTPS variable pointed to next. In CVE-2026-8927, the failure mode is connection or handle reuse: a long-running process (think a CI job iterating over many targets) that changes http_proxy/https_proxy between calls but reuses the same curl handle could carry stale Digest authentication state from proxy A into a request destined for proxy B. Both bugs matter more than they might look on paper because proxy credentials are frequently shared, long-lived service-account passwords rather than short-lived tokens — exactly the kind of secret an unintended second recipient shouldn't get.
What makes storing proxy credentials in config files risky in practice?
npm is the clearest documented example. npm's supported method for authenticating to a proxy is embedding user:pass directly in the proxy or https-proxy value inside .npmrc, and that file is stored as plaintext on disk by design — there's no built-in encryption layer. The npm project has had an open feature request, npm/npm#11209, asking for encrypted proxy credential storage, unresolved for years. The practical exposure isn't theoretical: on a shared build agent or CI runner, .npmrc is readable by any process running as the same user, including build steps for unrelated projects, third-party install scripts, or a compromised dependency's postinstall hook. Anywhere a proxy password sits in a dotfile checked into a home directory, synced via a golden CI image, or copied between machines in an onboarding script, it inherits every risk of any other plaintext secret — except it's rarely treated with the same scrutiny as an API key, because "it's just a proxy password" undersells what that credential can reach.
How should teams scope and rotate proxy credentials to limit blast radius?
Treat a proxy credential as a shared secret with a defined blast radius, not a one-time setup step. Concretely: use a dedicated service account per proxy rather than reusing an individual's or a shared team's domain credentials, so a leak doesn't expose broader network authentication; set no_proxy/NO_PROXY explicitly to exclude internal hosts that don't need to transit the proxy at all, shrinking the set of requests carrying the credential; and rotate proxy passwords on the same cadence as other service-account secrets rather than leaving them static for years because "nothing rotates the proxy password automatically." Where a proxy supports it, prefer short-lived, token-based proxy authentication over static basic-auth passwords — a leaked token with a defined expiry is a smaller incident than a leaked password that's valid until someone remembers to change it. None of this is CLI-tool-specific; it's the same credential-hygiene discipline applied to a category of secret that tends to get configured once and never revisited.
How does Safeguard's own CLI handle proxy configuration and credential storage?
Safeguard's CLI documents proxy settings under proxy.http, proxy.https, and proxy.no_proxy in ~/.safeguard/config.yaml, with HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables available as overrides — the same layered model most CLI tools use, which is exactly why the discipline above applies to it too. Where Safeguard diverges from the .npmrc pattern is credential storage: rather than requiring API keys or proxy secrets to live in plaintext YAML, the CLI supports OS-keychain-backed storage via credentials.use_keychain: true and safeguard auth set-key --secure, which stores the key using the operating system's native credential store instead of a config file any local process can read. That's the same shift teams should be pushing their other tools toward: keychain or secret-manager-backed storage for anything long-lived, plaintext config reserved for values that genuinely aren't sensitive, like the proxy hostname itself.