Vault hardening — persist a canonical master-key verifier (authenticated ground truth) #1

Open
opened 2026-07-15 08:59:06 +00:00 by James · 0 comments
Owner

Title: Vault hardening — persist a canonical master-key verifier (authenticated ground truth)

Labels: security, enhancement, deferred

Summary

ITFlow's credential vault has no authenticated site master key. Every path (web
login, admin API-token creation, and the Phase 3 credential-login vault bootstrap)
recovers the master key by unauthenticated AES-CBC decryption of a per-user
"wrap". AES-CBC does not fail on a wrong key — it returns garbage that can
occasionally pass a shape check. There is no MAC anywhere to confirm "this is the
real master key."

Impact

If a user's stored wrap becomes inconsistent with their password — realistically
after an admin force-resets that user's password without re-wrapping their
user_specific_encryption_ciphertext, or a DB restore/edit — then login recovers
a wrong-but-valid-shaped master. If a write then proceeds under it, the new
credential is encrypted with a junk key and is permanently unreadable. Reads are
non-destructive (garbage just fails to decrypt).

Current mitigation (shipped, Phase 3)

api/v2/auth/login.php provisions credential-session vault access only when the
recovered master's HMAC matches the verifier stored on a manual admin token
(auth_site_master_verifier() in api/v2/auth/includes/vault_wrap.php), which was
created from an admin's live web session. This blocks the realistic path (a
reset user's stale wrap won't match). The residual gap: the admin token's own
verifier is itself derived from an unvalidated decrypt, so if the admin's own wrap
were stale the ground truth would be wrong (self-evident — the admin's web vault
would be broken).

Proper fix (this issue)

  1. New installs: when the site master key is first generated
    (setup/index.php, scripts/setup_cli.php), also persist
    HMAC('itflow-...-master', master) as an immutable canonical verifier
    (fork-owned storage: a small additive table or settings column).
  2. Existing installs: one-time admin action that seeds the canonical verifier
    from the admin's live in-use session master (corroborated by the admin
    actively reading the vault). Fail closed (no write-capable vault) until seeded.
  3. Gate ALL vault WRITE provisioning (login + manual-token creation) on
    hash_equals(canonical_verifier, HMAC(recovered_master)). Manual-token
    creation validates against the canonical verifier and never establishes or
    replaces it.

Additive, no re-encryption, no key change, no re-setup — but it does touch core
setup files, so it was deferred (2026-07-15) to keep core changes minimal.

References

  • Design: docs/AUTH-VAULT-PHASE3.md §3, §4b
  • Crypto: functions.php (setupFirstUserSpecificKey / decryptUserSpecificKey),
    admin/post/api_tokens.php:77-99, api/v2/credentials.php
Title: Vault hardening — persist a canonical master-key verifier (authenticated ground truth) Labels: security, enhancement, deferred ## Summary ITFlow's credential vault has no authenticated site master key. Every path (web login, admin API-token creation, and the Phase 3 credential-login vault bootstrap) recovers the master key by *unauthenticated* AES-CBC decryption of a per-user "wrap". AES-CBC does not fail on a wrong key — it returns garbage that can occasionally pass a shape check. There is no MAC anywhere to confirm "this is the real master key." ## Impact If a user's stored wrap becomes inconsistent with their password — realistically after an **admin force-resets that user's password without re-wrapping** their `user_specific_encryption_ciphertext`, or a DB restore/edit — then login recovers a wrong-but-valid-shaped master. If a **write** then proceeds under it, the new credential is encrypted with a junk key and is permanently unreadable. Reads are non-destructive (garbage just fails to decrypt). ## Current mitigation (shipped, Phase 3) `api/v2/auth/login.php` provisions credential-session vault access only when the recovered master's HMAC matches the verifier stored on a **manual admin token** (`auth_site_master_verifier()` in `api/v2/auth/includes/vault_wrap.php`), which was created from an admin's live web session. This blocks the realistic path (a reset *user's* stale wrap won't match). The residual gap: the admin token's own verifier is itself derived from an unvalidated decrypt, so if the admin's own wrap were stale the ground truth would be wrong (self-evident — the admin's web vault would be broken). ## Proper fix (this issue) 1. **New installs:** when the site master key is first generated (`setup/index.php`, `scripts/setup_cli.php`), also persist `HMAC('itflow-...-master', master)` as an immutable canonical verifier (fork-owned storage: a small additive table or settings column). 2. **Existing installs:** one-time admin action that seeds the canonical verifier from the admin's live in-use session master (corroborated by the admin actively reading the vault). Fail closed (no write-capable vault) until seeded. 3. Gate ALL vault WRITE provisioning (login + manual-token creation) on `hash_equals(canonical_verifier, HMAC(recovered_master))`. Manual-token creation validates against the canonical verifier and never establishes or replaces it. Additive, no re-encryption, no key change, no re-setup — but it does touch core setup files, so it was deferred (2026-07-15) to keep core changes minimal. ## References - Design: `docs/AUTH-VAULT-PHASE3.md` §3, §4b - Crypto: `functions.php` (setupFirstUserSpecificKey / decryptUserSpecificKey), `admin/post/api_tokens.php:77-99`, `api/v2/credentials.php`
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
James/itflow#1
No description provided.