Why Does Your Cloud CLI Keep Picking the Wrong Account? Five Hidden Traps Explained

Most cloud CLIs pick their execution account from env vars, project files, or global state — not login status — and AI agents are amplifying the hidden mismatches.
The article exposes a common but overlooked problem: the account a cloud CLI command actually runs as is often not the one the user thinks. Five real cases explain why — GH_TOKEN silently overriding login state; project folders (.vercel/project.json, supabase project-ref, wrangler.toml) deciding the account; kubectl's first-wins config merge; global state commands like az account set being changed by other terminals; and duplicate names forcing reliance on IDs. AI coding agents worsen the risk since they don't confirm the active account and approval prompts show only the command. The author built cloudpin to pin accounts by ID and block wrong-account commands across az, aws, gcloud, vercel, gh, kubectl, helm, supabase, and wrangler.
You type vercel deploy, gh pr merge, or kubectl apply — but which account is it actually running on? Most people would say, "Obviously, the one I'm logged into." But that's often not the case, and there's no warning on screen. Every CLI decides which account to use based on command-line arguments, environment variables, files in the current directory, and files in the user's home directory — and the check order differs from tool to tool. While building cloudpin, one developer ran into five typical cases, all verified against current versions.

1. Environment Variables Quietly Override Your Login
gh auth status shows you're logged in, but if GH_TOKEN or GITHUB_TOKEN exists, gh will use that token for all commands instead of your login credentials. Similarly, VERCEL_TOKEN, SUPABASE_ACCESS_TOKEN, and CLOUDFLARE_API_TOKEN override the login state of their respective CLIs.
These variables are often set once and forgotten — maybe in a .env file, a CI secret copied locally, or an old shell config. From then on, what you see as your login and what your command actually runs as are no longer the same thing, and there's no on-screen hint.
CLI tools generally follow the design principle of "explicit tokens take precedence over login sessions," stemming from real CI/CD needs: in unattended pipelines, interactive login isn't possible, so credentials must be injected via environment variables. That's why tools like gh and vercel treat GH_TOKEN and VERCEL_TOKEN as higher-priority credential sources than ~/.config/gh/hosts.yml or an OAuth session. gh auth status only checks locally stored login credentials and is unaware of environment variables — this is the root cause of the disconnect between "login status" and "execution account." The danger lies in three things: the token may have been generated for a different account or organization; the token's validity period and scope may not match the current task; and after a .env file is auto-loaded by tools (like dotenv or direnv), even the user doesn't know when the variable took effect. To troubleshoot, use env | grep -iE '(TOKEN|API_KEY)' for a quick check.
2. The Project Folder Determines the Account
Several CLIs read the target account from the project folder rather than login status:
- Vercel: A linked project (
.vercel/project.json) sends project-level requests to the team it was linked to. Observed on Vercel CLI 50.35:--teamchanges account-level requests but doesn't affect these, whereasVERCEL_ORG_IDdoes. Thecurrentmarker invercel teams lsonly shows the global team and has nothing to do with the folder. - Supabase: Commands go to the project recorded in
supabase/.temp/project-ref(written bysupabase link), unless--project-reforSUPABASE_PROJECT_IDspecifies otherwise. Copying the folder copies the link. - Cloudflare Wrangler:
account_idinwrangler.tomltakes precedence overCLOUDFLARE_ACCOUNT_ID. There's even a TODO in the source planning to swap the priority in v5. If the config file specifies a different account, then setting the environment variable "just to be safe" accomplishes nothing.
So cd ../other-project && deploy might land on a different account in the same terminal, under the same login.
The "project binding" mechanism was designed so that a code repository always corresponds to one cloud project, avoiding team members connecting to different environments. Vercel writes orgId and projectId into .vercel/project.json during vercel link, and thereafter all project-level commands (deploys, env vars, logs) strictly follow that file; only account-level commands (like vercel teams ls) query global login state. Supabase's supabase link works the same way, writing the project ref to supabase/.temp/project-ref. This means repository clones, folder copies, and git worktree all "inherit" the binding. Think of it as a contract attachment: it travels with the code, not with the person. So cd-ing into another directory is equivalent to switching to a different account view, with no visual cue in the terminal itself.
3. Config Files Merge, and the First One Wins
KUBECONFIG can list multiple files. kubectl merges them, and for each value, the first file that sets it wins. Add a file to the front of the list and your prod context might have the same name but point elsewhere.
Even sneakier: kubectl config view --minify shows the context you expect, but it ignores --cluster, while the actual request uses it. In other words, the command you use to check may not be consistent with the command that actually executes.
kubectl's config merge rules are the opposite of most people's intuition. It follows "first-wins": files are traversed in the order listed in KUBECONFIG, and a field is adopted the first time it appears — any same-named definitions in later files are ignored. This differs from Kubernetes resource merging, where "the latter overrides the former," and is also the reverse of how most shell environment variables override. So when you put prod-kubeconfig at the front of the list, your local minikube or kind context may be silently replaced by a production cluster's same-named context. Worse still, --minify outputs the "minimal usable config," which only retains fields referenced by the current context — so it may be inconsistent with the actual merged config in effect. This is a common pitfall when using it for verification. For reliable cross-checking, first look at the merged result from kubectl config view, then cross-reference with the order in KUBECONFIG.
4. Someone Else Changed the Global State
az account set, gh auth switch, and gcloud config configurations activate all rewrite files in your home directory. Every terminal and every tool shares these files. Switch in one window to check client data, and an hour later a deploy launched in another window goes to that client.
Some errors don't even throw. On gcloud SDK 588, specifying a nonexistent name with --configuration doesn't error — instead you get an empty config and exit code 0.
5. Names Are Not IDs
- In the author's own Azure account, multiple subscriptions are all named "Azure subscription 1" — only the subscription ID distinguishes them.
- Kubernetes context names are personal: the same cluster is called
prodon one laptop andacme-prod-adminon another. - AWS CLI aliases (
~/.aws/cli/alias) can replace built-in commands, soaws s3 lsmight not bes3 ls. - gcloud puts resource names after the verb:
gcloud compute instances delete describewill delete an instance named "describe."
New Risks Posed by AI Agents
Coding agents run these commands for you, and unless you explicitly ask, they won't stop to check the active account. When the author started using an agent for personal Azure infrastructure projects, every change was approved by him — but the approval prompt only showed the command, not which account it would run on. So he added the same sentence to almost every request: check which account you're logged into first. It works, but only when he remembers to say it — and that's exactly what bothers him.
The way AI coding agents operate amplifies all the risks above. They execute multiple CLI commands in sequence, auto-fix errors, and retry without confirmation — a completely different rhythm from the traditional "human presses a key, one command executes." More critically, the granularity of permission prompts is the issue: most agents only display the command text (like az group delete --name prod-rg), not the execution context (which subscription, which account, which region). The user approves the "action," not the "target of the action." Solutions being discussed in the industry include having agents explicitly output a context summary before each destructive operation, or introducing "dry-run first" workflows. cloudpin as an agent hook is one of the few attempts to institutionalize this layer of context checking, but the trust boundary between automation tools and human review is still evolving.
The Solution: cloudpin
To address this, the author built cloudpin. You pin the account a project uses by ID in .cloudpin.yml (because names are duplicated). Before any protected command runs, cloudpin uses that command's own arguments, environment, and folder to compute which account it will use, and blocks the command if it's not the pinned one. If it can't determine the account, it blocks the command and explains why. It works in terminals (shell wrapper) and agent hooks (Claude Code, Codex, Cursor, Copilot CLI, Antigravity, and Gemini CLI).
It covers az, aws, gcloud, vercel, gh, kubectl, helm, supabase, and wrangler. cloudpin explain -- <command> shows what decision it would make for any command and why, without running it.
Coexisting with Existing Tools
cloudpin doesn't manage credentials or switch accounts — it coexists with tools that do:
- aws-vault and granted issue short-term AWS credentials; cloudpin checks whether they correspond to the correct account.
- kubectx and kubens quickly switch contexts; cloudpin blocks commands when the switch is wrong.
- direnv sets per-folder variables; cloudpin checks which account those variables point to.
cloudpin is only about a week old and still under active development. Upcoming plans include a Claude Code plugin, a GitHub Action, and Homebrew and Scoop installers.
To try it: npm install --global cloudpin, then run cloudpin init in your project. If it gets the account wrong in your setup, please file an issue — that's the feedback the author needs most.
One-line Summary
Most cloud CLIs pick their actual execution account based on environment variables, project files, or global state — not login status — and these hidden mismatches are being amplified by AI agents.
Paragraph Summary
The article reveals a widespread but overlooked problem in cloud CLI tools: the account a command actually runs as is often not the one the user thinks. Through five real cases, the author explains the causes — environment variables (like GH_TOKEN) silently overriding login state; project folders (.vercel/project.json, supabase project-ref, wrangler.toml) determining the account rather than login credentials; kubectl merging multiple configs where the first file to set a value wins; global state commands like az account set being changed by other terminals and affecting the current window; and duplicate names forcing reliance on IDs to distinguish resources. The rise of AI coding agents compounds the risk, because they don't proactively confirm the active account and approval prompts show only the command, not the target account. The author built cloudpin to pin accounts by ID via .cloudpin.yml, predicting and blocking wrong-account commands before any protected command runs, covering az, aws, gcloud, vercel, gh, kubectl, helm, supabase, and wrangler.
Related articles

From Photons to Production: An Open-Source Computer Vision Engineering Reading Path
Reddit user open-sources a computer vision engineering reading path with 16 chapters from image formation to production deployment, emphasizing primary sources, dependency order, and reproducible benchmarks to help engineers understand why models fail and build reliable vision systems.

Prompt Failures? The Truth About Why AI Agents Struggle in Production—and How to Fix It
A Reddit developer built Agents with Copilot and Gemini but faced unstable behavior. This article analyzes three gaps in prompt engineering for Agent scenarios and offers three practical paths to reliable Agent deployment, including structured prompts, workflow-first approaches, and building an evaluation loop.

Tesla Robotaxi to Open Private Vehicle Access Next Year: Promise or Pipe Dream?
At its Q3 earnings call, Tesla said owners can add their cars to the Robotaxi fleet next year. We analyze the technical basis, Musk's missed deadlines, business logic, and competition.