# No hardcoded database credentials in source code

- **Pattern:** `ab-000913` (`database-design-operations.security-access.no-hardcoded-credentials`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000913
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000913)

## Why it matters

A hardcoded database connection string or password in source code is exposed to every developer with repo access, in every git clone, in CI logs, and in any code review tool. Once committed to git history, it is permanently visible even after removal — any attacker who ever had read access to the repo has the credential. CWE-798 (use of hard-coded credentials) and OWASP A07 both recognize this as a critical failure because the attacker does not need to compromise the server — they only need to access the repository. Credential rotation after exposure is the only remediation, and it requires a production deployment under time pressure.

## Severity rationale

Critical because a hardcoded credential in source code is permanently accessible to anyone with repository read access, including past collaborators and any platform that integrated with the repo.

## Remediation

Load all database credentials from environment variables. Ensure `.env` is in `.gitignore`. Provide `.env.example` with placeholder values only — never real connection strings.

```ts
// WRONG — never hardcode credentials
// const pool = new Pool({ connectionString: 'postgres://admin:prod_pass@db.example.com/app' })

// CORRECT — load from environment
if (!process.env.DATABASE_URL) throw new Error('DATABASE_URL is required')
export const pool = new Pool({ connectionString: process.env.DATABASE_URL })
```

```bash
# .gitignore — confirm these are excluded
.env
.env.local
.env.production
```

```
# .env.example — placeholders only (commit this)
DATABASE_URL=postgresql://USER:PASSWORD@HOST:PORT/DATABASE
```

If credentials were accidentally committed: rotate them immediately, then audit git history with `git log --all -S "the_exposed_value"` to assess the exposure window.

## Detection

- **ID:** `no-hardcoded-credentials`
- **Severity:** `critical`
- **What to look for:** Enumerate every file in src/ and lib/ containing database connection strings and search the codebase for database connection strings, passwords, or credentials that appear directly in source files. Look for: (1) `DATABASE_URL = "postgres://user:password@host/db"` as a hardcoded string in .ts/.js/.py files. (2) Connection options objects with literal password values: `{ password: "mysecretpassword123" }`. (3) Credentials in configuration files that are committed to git (`config/database.yml`, `appsettings.json`, `application.properties`). (4) `.env` files with real credentials committed to the repository (check git history too if suspicious). Check `.env.example` to confirm it contains only placeholder values (e.g., `DATABASE_URL=postgresql://USER:PASSWORD@HOST:PORT/DATABASE` not a real connection string). Check `.gitignore` to confirm `.env` and `.env.local` are excluded.
- **Pass criteria:** All database credentials are loaded from environment variables at runtime — fewer than 1 hardcoded credential found after searching at least 3 source directories. No credentials exist in source files. `.env` is in `.gitignore`. `.env.example` contains only placeholder/example values with no real credentials. Before evaluating, extract and quote the variable names and assignment patterns (not actual secret values) of any credential-like constants found.
- **Fail criteria:** Database password or connection string hardcoded in any source file. `.env` file committed to git with real credentials. Credentials found in config files not excluded by `.gitignore`.
- **Skip (N/A) when:** N/A — always applicable for any project with a database.
- **Detail on fail:** Specify where credentials are found. Example: `"Hardcoded DATABASE_URL found in src/lib/db.ts: 'postgres://admin:prod_password_123@db.example.com/myapp'."` or `".env file is not in .gitignore — credentials may be committed to git history."`.
- **Remediation:** Move all credentials to environment variables:

  ```ts
  // WRONG — hardcoded credentials in source
  // const pool = new Pool({ password: 'mysecretpassword' })  // NEVER DO THIS

  // CORRECT — load from environment
  import { Pool } from 'pg'

  if (!process.env.DATABASE_URL) {
    throw new Error('DATABASE_URL environment variable is required')
  }

  export const pool = new Pool({
    connectionString: process.env.DATABASE_URL,
  })
  ```

  ```bash
  # .gitignore — ensure .env files are excluded
  .env
  .env.local
  .env.*.local
  .env.production  # never commit production env
  ```

  ```
  # .env.example — placeholders only (commit this file)
  DATABASE_URL=postgresql://USER:PASSWORD@HOST:PORT/DATABASE
  ```

  If credentials were accidentally committed, rotate them immediately. Check git history with `git log --all -S "password_value"` to assess exposure. Use `git filter-repo` to remove credentials from history if needed.

---

## External references

- cwe CWE-798
- owasp A07

Taxons: cryptography-and-secrets

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