Skip to content

Security

Melvin PETIT edited this page Jun 22, 2026 · 2 revisions

Security

Security is a first-class concern: DataShield handles employee PII and third-party credentials. This page summarizes the controls in the codebase and the CI pipeline.

Secrets at rest

Directory configs, breach-provider API keys, and webhook URLs are encrypted with AES-256-GCM before they touch the database (src/lib/directory/crypto.ts):

  • The 32-byte key is derived from DIRECTORY_ENCRYPTION_KEY via SHA-256, so any sufficiently long secret normalizes to a valid key.
  • A fresh 12-byte random IV (the recommended GCM nonce) is generated per encryption; the stored blob is base64(iv || authTag || ciphertext).
  • The 16-byte GCM auth tag is verified on decrypt, so tampered ciphertext fails closed.
  • No silent fallback: a missing or under-32-character key throws immediately rather than degrading to plaintext.

Only display-safe hints are stored unencrypted: keyHint (key suffix) and urlHint (webhook host only).

Authentication and sessions

  • Auth.js (next-auth v5) issues and validates sessions.
  • Passwords are hashed with bcrypt (hashedPassword).
  • src/middleware.ts protects every route except api/auth, static assets, and /login.

Authorization

All API authorization goes through one module (apiAuth.ts) with two guards, requireAuth and requireAdmin. Queries are always scoped by companyId so tenants are isolated. See Roles and Permissions.

SCIM token handling

Inbound SCIM requests authenticate with a per-connection bearer token compared in constant time (crypto.timingSafeEqual) to neutralize timing attacks. Failures (missing token, unknown connection, unreadable config) all return 401, never 500. See SCIM Provisioning.

Rate limiting

src/lib/rateLimit.ts is a fixed-window counter. Scans are capped at 5 per company per minute. It is in-memory and per-instance, sufficient for a single-node deployment; move it to a shared store before scaling horizontally.

Outbound notification safety

Webhook dispatch (src/lib/webhooks.ts) only fires for events at or above each webhook's minSeverity, decrypts URLs only at send time, and swallows network errors so a dead endpoint never breaks a scan. See Notifications.

Live remediation

Remediation acts on the customer's live IdP (revoke sessions, force password resets) and is off by default (Company.remediationEnabled). The endpoint refuses with 403 until it is deliberately enabled, every attempt is recorded append-only in RemediationAction, and a directory type can only run the actions its API supports. See Remediation.

SIEM export token

The SIEM pull feed authenticates with a per-company bearer token, stored encrypted (AES-256-GCM) and compared in constant time; a missing or unreadable token returns 401. The feed is rate limited (60/min) and capped (1000 alerts). See SIEM Integration.

CI security gates

Three workflows enforce security on every PR and push (see Development):

  • Security (security.yml): npm audit --audit-level=high, Gitleaks and TruffleHog secret scanning over full history, and Dependency Review on PRs. Runs weekly on a schedule to catch newly disclosed advisories.
  • CodeQL (codeql.yml): static analysis.
  • Compliance (compliance.yml): PR title and content checks, ASCII-only enforcement, dependency advisory checks.

Reporting a vulnerability

Use the policy in .github/SECURITY.md in the repository. Do not open a public issue for security reports.

Clone this wiki locally