Database encryption is enabled for sensitive data at rest
Why it matters
PCI-DSS 4.0 Req 3.5 mandates encryption of stored account data; Req 3.3 prohibits storage of sensitive authentication data post-authorization. A database without encryption at rest means any storage-layer compromise — a stolen disk, a snapshot shared to the wrong account, or a cloud misconfiguration — exposes cardholder data in plaintext. NIST SP 800-53 SC-28 and OWASP A02 (Cryptographic Failures) both treat unencrypted data stores as high-severity findings. For managed services like RDS or Supabase, missing storage_encrypted = true means the infrastructure configuration actively opts out of protection that is trivially available.
Severity rationale
Critical because an unencrypted database volume means a storage-layer breach yields plaintext cardholder data with no decryption barrier, satisfying PCI-DSS Req 3.5 as a direct violation.
Remediation
Enable encryption at rest before the database instance is created — this cannot be changed on a running RDS instance without a snapshot-and-restore cycle. Store the encryption key in a managed key service, never in the codebase. Reference terraform/main.tf for infrastructure changes.
resource "aws_db_instance" "main" {
storage_encrypted = true
kms_key_id = aws_kms_key.db.arn
}
For Supabase, encryption at rest is managed automatically but verify it in the project dashboard under Settings > Infrastructure. For self-managed PostgreSQL, add column-level encryption via pgcrypto as a supplementary control where field-level sensitivity is highest.
Detection
-
ID:
database-encryption -
Severity:
critical -
What to look for: Count all database instances referenced in infrastructure code (Terraform, CloudFormation, docker-compose, Kubernetes manifests). For each instance, check for encryption-at-rest configuration. For managed services (RDS, Cloud SQL, Azure SQL, Supabase), look for
storage_encrypted = trueor equivalent in service configs. For self-managed databases, look for Transparent Data Encryption (TDE), file-level encryption, or encrypted volume configs. Count the number of encryption key references (KMS, vault, etc.). -
Pass criteria: Database encryption at rest is enabled on at least 1 database instance. For managed services,
storage_encryptedor equivalent is set totruein infrastructure code. For self-managed databases, encryption is enabled and keys are stored separately from the database (at least 1 KMS or key management reference found). Report the count: X of Y database instances have encryption enabled. -
Fail criteria: Database has no encryption at rest enabled, or encryption is disabled explicitly (e.g.,
storage_encrypted = false). Do NOT pass when encryption is mentioned only in comments or documentation but not in actual infrastructure configuration. -
Skip (N/A) when: No database instances found in the project (no database dependencies in
package.json, no ORM config, no database connection strings). -
Detail on fail: Specify the database type and missing encryption. Example:
"PostgreSQL database configured without Transparent Data Encryption (TDE). Encryption at rest not enabled. 0 of 1 instances encrypted."or"RDS instance created with StorageEncrypted: false in terraform/main.tf line 42" -
Cross-reference: See
ecommerce-pci.cardholder-data.cde-isolated(CDE isolation),ecommerce-pci.cardholder-data.no-default-credentials(credential management). -
Remediation: Enable encryption at rest on your database. For Supabase/PostgreSQL:
-- Supabase manages TDE automatically, but verify in dashboard -- For self-managed PostgreSQL with pgcrypto CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE TABLE sensitive_data ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), encrypted_value BYTEA, created_at TIMESTAMP DEFAULT NOW() ); -- For AWS RDS -- Enable in Terraform: resource "aws_db_instance" "main" { storage_encrypted = true kms_key_id = aws_kms_key.db.arn }Verify encryption is enabled in your database service dashboard. Store encryption keys in a key management service (AWS KMS, Azure Key Vault, Google Cloud KMS), never in your codebase.
External references
- pci-dss:4.0 · Req 3.5 — Primary account number is secured wherever stored
- pci-dss:4.0 · Req 3.3 — Sensitive authentication data is not stored after authorization
- cwe · CWE-312 — Cleartext Storage of Sensitive Information
- owasp:2021 · A02 — Cryptographic Failures
- nist:rev5 · SC-28 — Protection of Information at Rest
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ecommerce-pci·automated