Skip to content

fix(cli/configure): write .env at mode 0o600 to protect LLM API keys#1969

Open
JAE0Y2N wants to merge 1 commit into
microsoft:mainfrom
JAE0Y2N:harden-env-file-perms
Open

fix(cli/configure): write .env at mode 0o600 to protect LLM API keys#1969
JAE0Y2N wants to merge 1 commit into
microsoft:mainfrom
JAE0Y2N:harden-env-file-perms

Conversation

@JAE0Y2N
Copy link
Copy Markdown

@JAE0Y2N JAE0Y2N commented May 19, 2026

Summary

The configure subcommand at packages/cli/src/configure.ts:186 prompts the user for their LLM provider API keys and patches them into a .env file via writeFile(filePath, updatedLines.join(" "), "utf-8") with no mode argument. On macOS and most Linux defaults (umask 022) the file lands at 0o644 — world-readable. Any local account or process that can traverse the working directory can recover the keys (OPENAI_API_KEY, ANTHROPIC_API_KEY, AZURE_OPENAI_API_KEY, etc.) and use them under the user's account quota.

This PR adds { mode: 0o600 } to the writeFile call (applies on file creation) plus a follow-up chmod(filePath, 0o600) (wrapped in try/catch for Windows) so pre-existing .env files at 0o644 converge to 0o600 on the next save.

Files changed

  • packages/cli/src/configure.ts — added chmod to the fs/promises import, passed { encoding: "utf-8", mode: 0o600 } to writeFile, added a follow-up chmod.

Verification

import { writeFile } from "fs/promises";
import { statSync } from "fs";

await writeFile("/tmp/genai-test.env", "OPENAI_API_KEY=sk-...
");
console.log((statSync("/tmp/genai-test.env").mode & 0o777).toString(8));  // 644 on default umask 022

After the PR: 600.

Context

Same CWE-732 finding class as huggingface/huggingface_hub#4234 (merged-approved), prisma/prisma#29568, eosphoros-ai/DB-GPT#3077, cline/cline#10893, replicate/cli#111, musistudio/claude-code-router#1399, anthropics/claude-cookbooks#642 filed today across the AI-tooling ecosystem. Industry baseline (GitHub CLI / AWS CLI / Google Cloud SDK / Stripe CLI / Pulumi) is 0o600 for credential files.

The `configure` subcommand prompts the user for their LLM provider API
keys (OPENAI_API_KEY, ANTHROPIC_API_KEY, AZURE_OPENAI_API_KEY, etc.) and
patches them into the `.env` file via `writeFile(filePath, content, "utf-8")`
with no `mode` option. On macOS and most Linux defaults (umask 022) that
lands the file at 0o644 — world-readable. Any local account or process
that can traverse the home / working directory can recover the keys and
use them under the user's account quota.

This commit:
- Adds `chmod` to the `fs/promises` import.
- Passes `{ encoding: "utf-8", mode: 0o600 }` to `writeFile` so a freshly-
  created `.env` is atomically restricted to the user.
- Adds a follow-up `await chmod(filePath, 0o600)` (wrapped in try/catch
  for Windows) so overwrites of a pre-existing `.env` at 0o644 converge
  to 0o600 on the next save.

Mirrors industry-baseline credential-file handling (GitHub CLI's
~/.config/gh/hosts.yml, AWS CLI's ~/.aws/credentials at 0o600).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JAE0Y2N
Copy link
Copy Markdown
Author

JAE0Y2N commented May 20, 2026

@microsoft-github-policy-service agree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant