# Environment variables for sensitive configuration

- **Pattern:** `ab-000660` (`cli-quality.config-distribution.env-vars`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000660
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000660)

## Why it matters

API keys and tokens passed as command-line flags appear in shell history (`~/.bash_history`, `~/.zsh_history`), in `ps aux` output visible to other users on the same machine, and in CI log output if the command is echoed before execution. CWE-214 (Sensitive Information in Command Line Arguments) documents this exact exposure vector. A contractor running `mytool --api-key sk-live-abc123 deploy` on a shared build server has just written that key into a file that persists after logout. Environment variables avoid all three exposure paths: they are not logged by the shell history, not visible in `ps` argument lists, and not echoed in CI unless explicitly printed.

## Severity rationale

Low because the exposure requires access to the user's shell history or process list — not network-accessible — but live API key leakage via `ps` on shared servers is a real, documented attack.

## Remediation

Accept sensitive values via environment variables and document the supported names in `--help`:

```ts
program
  .option('--api-key <key>', 'API key (or set MYTOOL_API_KEY env var)')
  .action((opts) => {
    const apiKey = opts.apiKey ?? process.env.MYTOOL_API_KEY
    if (!apiKey) {
      console.error('Error: API key required. Set MYTOOL_API_KEY or pass --api-key')
      process.exit(2)
    }
  })
```

```python
@cli.command()
@click.option('--api-key', envvar='MYTOOL_API_KEY',
              help='API key (or set MYTOOL_API_KEY env var)')
def deploy(api_key):
    if not api_key:
        raise click.UsageError('API key required: set MYTOOL_API_KEY or pass --api-key')
```

Follow the `TOOLNAME_VARNAME` convention in SCREAMING_SNAKE_CASE. Never log the value of the key — log only whether it was found.

## Detection

- **ID:** `env-vars`
- **Severity:** `low`
- **What to look for:** Count all environment variable references in the CLI code. For each, check if the CLI accepts sensitive values (API keys, tokens, passwords) and how they're configured. Look for `process.env.MYTOOL_API_KEY`, `os.environ.get('MYTOOL_TOKEN')`, `os.Getenv("MYTOOL_KEY")`. Verify that sensitive values can be set via environment variables rather than only command-line flags (which appear in shell history and `ps` output). Check that env var names follow the convention: `TOOLNAME_VARNAME` in SCREAMING_SNAKE_CASE.
- **Pass criteria:** Sensitive configuration (API keys, tokens, credentials) can be provided via environment variables. Env var names follow the `TOOLNAME_VARNAME` convention. The precedence order is documented: flags > env vars > config file > defaults — 100% of environment variables must be documented in --help or README. Report: "X environment variables referenced, all Y documented."
- **Fail criteria:** API keys or tokens must be passed as command-line flags (visible in shell history), or env vars are used but with non-standard names, or no documentation of env var support.
- **Skip (N/A) when:** The CLI does not accept any sensitive configuration — no API keys, tokens, or credentials. All checks skip when no CLI entry point is detected.
- **Detail on fail:** `"API key must be passed as --api-key flag — no environment variable support. The key will appear in shell history and ps output"` or `"Env var support exists but uses non-standard name 'key' instead of 'MYTOOL_API_KEY'"`
- **Remediation:** Environment variables keep secrets out of shell history:

  ```ts
  // Node.js — env var with flag override
  program
    .option('--api-key <key>', 'API key (or set MYTOOL_API_KEY env var)')
    .action((opts) => {
      const apiKey = opts.apiKey || process.env.MYTOOL_API_KEY
      if (!apiKey) {
        console.error('Error: API key required. Set MYTOOL_API_KEY or pass --api-key')
        process.exit(2)
      }
    })
  ```

  Document the supported env vars in `--help` output or a `mytool env` subcommand.

## External references

- cwe CWE-214

Taxons: cryptography-and-secrets, user-experience

HTML version: https://auditbuffet.com/patterns/ab-000660
