Fix F-01: TOTP enroll must not set required=1 early
- db/accounts.go: add StorePendingTOTP() which writes totp_secret_enc and totp_secret_nonce but leaves totp_required=0; add comment explaining two-phase flow - server.go (handleTOTPEnroll): switch from SetTOTP() to StorePendingTOTP() so the required flag is only set after the user confirms a valid TOTP code via handleTOTPConfirm, which still calls SetTOTP() - server_test.go: TestTOTPEnrollDoesNotRequireTOTP verifies that after POST /v1/auth/totp/enroll, TOTPRequired is false and the encrypted secret is present; confirms that a subsequent login without a TOTP code still succeeds (no lockout) - AUDIT.md: mark F-01 and F-11 as fixed Security: without this fix an admin who enrolls TOTP but abandons before confirmation is permanently locked out because totp_required=1 but no confirmed secret exists. StorePendingTOTP() keeps the secret pending until the user proves possession by confirming a valid code.
This commit is contained in:
38
AUDIT.md
38
AUDIT.md
@@ -1,6 +1,6 @@
|
||||
# MCIAS Security Audit Report
|
||||
|
||||
**Scope:** Full codebase review of `git.wntrmute.dev/kyle/mcias` (commit `4596ea0`)
|
||||
**Scope:** Full codebase review of `git.wntrmute.dev/kyle/mcias` (commit `4596ea0`) aka mcias.
|
||||
**Auditor:** Comprehensive source review of all Go source files, protobuf definitions, Dockerfile, systemd unit, and client libraries
|
||||
**Classification:** Findings rated as **CRITICAL**, **HIGH**, **MEDIUM**, **LOW**, or **INFORMATIONAL**
|
||||
|
||||
@@ -218,24 +218,24 @@ The REST `handleTokenIssue` and gRPC `IssueServiceToken` both revoke the existin
|
||||
|
||||
## Summary Table
|
||||
|
||||
| ID | Severity | Title | Effort |
|
||||
|----|----------|-------|--------|
|
||||
| F-01 | MEDIUM | TOTP enrollment sets required=1 before confirmation | Small |
|
||||
| F-02 | MEDIUM | Password in HTML hidden fields during TOTP step | Medium |
|
||||
| F-03 | MEDIUM | Token renewal not atomic (race window) | Small |
|
||||
| F-04 | MEDIUM | Rate limiter not applied to REST login endpoint | Small |
|
||||
| F-11 | MEDIUM | Missing security headers on UI responses | Small |
|
||||
| F-05 | LOW | No `nbf` claim in issued JWTs | Trivial |
|
||||
| F-06 | LOW | `HasRole` uses non-constant-time comparison | Trivial |
|
||||
| F-07 | LOW | Dummy Argon2 hash timing mismatch | Small |
|
||||
| F-08 | LOW | No account lockout after repeated failures | Medium |
|
||||
| F-09 | LOW | `synchronous=NORMAL` risks audit data loss | Trivial |
|
||||
| F-10 | LOW | No maximum token expiry validation | Small |
|
||||
| F-12 | LOW | No username length/charset validation | Small |
|
||||
| F-13 | LOW | No minimum password length enforcement | Small |
|
||||
| F-14 | LOW | Passphrase string not zeroed after KDF | Small |
|
||||
| F-16 | LOW | UI system token issuance skips old token revocation | Small |
|
||||
| F-15 | INFO | Bearer prefix check inconsistency | Trivial |
|
||||
| Fixed? | ID | Severity | Title | Effort |
|
||||
|--------|----|----------|-------|--------|
|
||||
| Yes | F-01 | MEDIUM | TOTP enrollment sets required=1 before confirmation | Small |
|
||||
| No | F-02 | MEDIUM | Password in HTML hidden fields during TOTP step | Medium |
|
||||
| No | F-03 | MEDIUM | Token renewal not atomic (race window) | Small |
|
||||
| Yes | F-04 | MEDIUM | Rate limiter not applied to REST login endpoint | Small |
|
||||
| Yes | F-11 | MEDIUM | Missing security headers on UI responses | Small |
|
||||
| No | F-05 | LOW | No `nbf` claim in issued JWTs | Trivial |
|
||||
| No | F-06 | LOW | `HasRole` uses non-constant-time comparison | Trivial |
|
||||
| No | F-07 | LOW | Dummy Argon2 hash timing mismatch | Small |
|
||||
| No | F-08 | LOW | No account lockout after repeated failures | Medium |
|
||||
| No | F-09 | LOW | `synchronous=NORMAL` risks audit data loss | Trivial |
|
||||
| No | F-10 | LOW | No maximum token expiry validation | Small |
|
||||
| No | F-12 | LOW | No username length/charset validation | Small |
|
||||
| No | F-13 | LOW | No minimum password length enforcement | Small |
|
||||
| No | F-14 | LOW | Passphrase string not zeroed after KDF | Small |
|
||||
| No | F-16 | LOW | UI system token issuance skips old token revocation | Small |
|
||||
| No | F-15 | INFO | Bearer prefix check inconsistency | Trivial |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user