A hardcoded SendGrid or Mailgun API key in a committed source file is a credential that any engineer with repository read access — and any attacker who gains access to the repo, a build artifact, or a public GitHub fork — can use immediately to send email at your expense, under your sending domain, to any recipient list. This maps to OWASP A02 (Cryptographic Failures) and CWE-798 (Use of Hard-coded Credentials). The damage is not theoretical: repositories are leaked, build logs are captured, and Docker image layers are extracted. Committing credentials is an irreversible exposure until the key is rotated.
Critical because a committed API key grants immediate unauthorized send access to the account and cannot be made safe after the fact without key rotation.
Load all ESP credentials via process.env and fail loudly at startup if the variable is absent, in lib/esp-client.ts:
const apiKey = process.env.SENDGRID_API_KEY
if (!apiKey) {
throw new Error('SENDGRID_API_KEY environment variable is required')
}
sgMail.setApiKey(apiKey)
Audit .env.example to confirm it contains only placeholder values like your-key-here. Rotate any key that has ever appeared in a committed file, even in a branch that was never merged.
ID: sending-pipeline-infrastructure.esp-integration.credentials-secure
Severity: critical
What to look for: Examine how the ESP client is initialized. Count all credential references (API keys, SMTP passwords, sending tokens) across the codebase — there must be 0 hardcoded string literals. Look in the ESP client initialization file, any configuration files committed to the repository, and check .env.example to confirm actual keys are not there. Verify the real credentials are loaded via process.env.* or a secrets manager (AWS Secrets Manager, Vault, Doppler).
Pass criteria: All ESP API keys and credentials are loaded from environment variables or a secrets manager at runtime. Count all credential references in the codebase — fewer than 1 hardcoded value must exist (i.e., zero). .env.example contains only placeholder values. Must not pass when even 1 credential string literal exists in any committed source file.
Fail criteria: An API key, SMTP password, or other credential is hardcoded as a string literal in any source file. Any committed configuration file contains a live credential.
Skip (N/A) when: Never — all credential handling must be checked.
Cross-reference: The Operational Resilience (Email) Audit's failure-recovery category verifies ESP failover — this check verifies the foundational credential security that failover depends on.
Detail on fail: Describe the credential exposure. Do not include the actual key value. Example: "SendGrid API key hardcoded as a string literal in lib/email.ts — will be committed to source control" or "SMTP password hardcoded in nodemailer transport config in config/mail.js"
Remediation: Load credentials from environment variables at module initialization:
// lib/esp-client.ts
import sgMail from '@sendgrid/mail'
const apiKey = process.env.SENDGRID_API_KEY
if (!apiKey) {
throw new Error('SENDGRID_API_KEY environment variable is required')
}
sgMail.setApiKey(apiKey)
export { sgMail }
For multiple environments, use a secrets manager to inject variables:
// For AWS Secrets Manager
import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager'
const client = new SecretsManagerClient({ region: 'us-east-1' })
const { SecretString } = await client.send(new GetSecretValueCommand({ SecretId: 'prod/email-service/sendgrid' }))
const { apiKey } = JSON.parse(SecretString!)