Repository navigation
CLI warns when the key comes from ./.env - #227
H-maximedelpit wants to merge 1 commit into
Conversation
ad9c1bb to
e89c4b4
Compare
e89c4b4 to
9ffbf0b
Compare
9ffbf0b to
b32c855
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit b32c855. Configure here.
| return CheckResult("login", True, detail) | ||
| ignored = credentials.key_file_warnings() | ||
| if ignored: | ||
| return CheckResult("login", False, "; ".join(ignored), fix="fix the file's owner and mode, or run `hai login`") |
There was a problem hiding this comment.
Doctor misdiagnoses missing API key
Low Severity
When no key resolves, check_login treats any key_file_warnings line as the login failure and offers only owner/mode repair. A leftover .env symlink or directory then replaces the "no API key configured" guidance, and that fix text does not match symlink or non-file rejections.
Reviewed by Cursor Bugbot for commit b32c855. Configure here.
abonneth
left a comment
There was a problem hiding this comment.
Thanks for digging into this. I think it guards the smaller risk though.
- A project
.envcan also setHAI_BASE_URL. The CLI then sends your real key from~/.config/hai/.envto that host. That's key theft, much worse than someone planting their own key, and this PR doesn't cover it. If we guard one thing, I'd guard that: warn on (or refuse) a non-default base URL coming from./.env. - The 0600 + owner check silently ignores keys that work today: Docker mounts, k8s secrets, files written by hand. I'd warn instead of ignoring.
- Warning on every command for a legit per-project key will teach people to tune it out.
_state()now prints. I'd keep it a plain getter.
~200 lines feels heavy for a heuristic. ~20 lines covering the base URL case plus one warning would get most of the value.
|
Closing: since #233 the CLI resolves credentials from the argument, then HAI_API_KEY, then ~/.config/hai/.env, and never reads a project .env. Both risks this PR guarded (a planted key, or a base URL pointing your real key at another host, coming from a cloned repo's .env) went away with it. The base-URL angle was the right one to flag, thanks. |


Purpose
Found during the security review of the
hai loginwork: the CLI reads./.envbefore the global key file, with no checks.hai runinside a cloned or forked repo that ships a.envwithHAI_API_KEYsends the user's prompts, files and vault secrets to the attacker's organization, silently. Independent of the login changes.What it does
./.env, every command prints once, on stderr (emitted from the shared state builder, somcp install,local,loginand--jsonmodes are covered; Bugbot finding): "Using HAI_API_KEY from .env. Make sure this key is yours: a cloned or forked repo can ship a .env that carries someone else's key on purpose, and your runs would then land in their account."hai doctorcarries the same sentence. The key value is never printed..envwithoutHAI_variables is ignored silently. A symlink in place of./.envis rejected.~/.config/hai/.envmust be a regular file owned by the current user with mode 600, ashai loginwrites it; otherwise it is ignored with a reason.--api-key,HAI_API_KEY,./.env, global file.What it does not do
Detection, not prevention: a reader who skims stderr still sends the run to the attacker's org. Accepted for now.
Alternatives rejected
./.env: honest project files are created with the umask (0644) like planted ones, so it would reject most legitimate files and teach people tochmodpast it.~/.config/hai/trusted): built and tested, then dropped as too heavy for now. Candidate follow-up if the warning proves insufficient../.envsupport: per-project keys are a used feature.Dependencies and merge order
None. Touches
app.pynear the client builder, so whicheverhai loginPR lands after it (#229 or #228) needs a small rebase.🤖 Generated with Claude Code
Note
Medium Risk
Changes authentication credential resolution and global key file trust rules; misconfiguration could block legitimate keys until permissions are fixed, while project
.envkeys remain usable with only a stderr warning.Overview
Hardens CLI credential loading and adds detection (not blocking) when
HAI_API_KEYcomes from a project.env, so runs in cloned repos with a planted key are less likely to go unnoticed.Credential rules in
credentials.py: only read env files that passkey_file_rejection(regular file; global~/.config/hai/.envmust be user-owned and mode600). Project.envis used only if it sets at least oneHAI_*variable; symlinks and unreadable/binary files are skipped without crashing. Ignored files surface viakey_file_warnings().User-facing behavior:
_state()prints those warnings plusPROJECT_ENV_WARNINGonce per process on stderr (including--json).hai doctorrepeats the project-key warning on success and fails login when keys are present but ignored. README documents the warning and global file permissions.Resolution order is unchanged:
--api-key→HAI_API_KEY→./.env→ global file.Reviewed by Cursor Bugbot for commit b32c855. Bugbot is set up for automated code reviews on this repo. Configure here.