Skip to content

[Security P5] Use constant-time comparisons and salted KDF for stored credential hashes #78

Description

@cursor

Summary

API tokens and ingest secrets are stored as plain SHA-256 hashes without per-credential salt or a slow KDF. Secret comparisons use non-constant-time equality checks.

Severity

Medium

Context

From full-codebase security review (2026-07-11). Priority remediation item #5.

Affected areas

  • apps/api/src/application/auth.ts:5-11 — SHA-256 hashing
  • apps/api/src/application/auth.ts:39-47 — bootstrap token compared with ===
  • apps/api/src/application/tokens.ts:52-53 — token hash storage
  • apps/api/src/application/ingest.ts:349-354 — ingest secret verification via Array.find + ===
  • apps/api/src/application/endpoints.ts:336 — endpoint secret hashing

Risk

  • Database leak enables faster offline hash comparison attacks
  • Timing side channels on secret/token verification (lower practical risk with high-entropy secrets, but worth hardening)
  • Bootstrap token comparison is especially sensitive if the token is weak

Recommendations

  • Use a slow KDF (e.g. PBKDF2, scrypt, or Argon2 via Web Crypto) with per-record salt for stored hashes
  • Compare fixed-length digests with constant-time equality (crypto.subtle.timingSafeEqual or equivalent)
  • For multiple active ingest secrets, compare all hashes in constant time without early exit
  • Enforce strong bootstrap secret length/entropy; disable bootstrap in production after initial provisioning

Acceptance criteria

  • Token and ingest secret hashes use salted slow KDF
  • All secret/token comparisons are constant-time
  • Migration path for existing hashed credentials is documented or implemented
  • Tests cover timing-safe comparison behavior
  • Bootstrap token handling is hardened

References

  • Security review findings: unsalted SHA-256, non-constant-time comparisons
  • Related spec: requirements/barestash-backend.spec.md

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions