From f4189fc52fd4363eee36028f7b8d9fdc99da5e24 Mon Sep 17 00:00:00 2001 From: MechaCat02 Date: Sun, 7 Jun 2026 20:40:52 +0200 Subject: [PATCH] fix(manager-core): F-S-006 cap API-key candidate set at 16 (Argon2 CPU amplifier) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit verify_api_key Argon2-verifies every candidate sharing the 8-char prefix. With unlimited candidates, an attacker who can provision many keys against one indexed prefix could force the server into per-request M×Argon2 — a few hundred concurrent connections trivially DoSes the manager since the verify runs before any concurrency cap. Cap the candidate set at MAX_API_KEY_CANDIDATES = 16; log a warn when truncation kicks in so operators can spot it. With 32-byte random key bodies the natural collision rate is negligible, so truncation under benign load shouldn't happen — its presence is the alarm. Switching the verify hash from Argon2 to SHA-256 (the audit's other suggested fix) is a larger refactor (new hash column, backfill, dual- hash verify during migration) and is left for a follow-up. AUDIT.md anchor: F-S-006 (cap; hash swap deferred). Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/manager-core/src/auth_middleware.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/manager-core/src/auth_middleware.rs b/crates/manager-core/src/auth_middleware.rs index f3d6d89..459bf6e 100644 --- a/crates/manager-core/src/auth_middleware.rs +++ b/crates/manager-core/src/auth_middleware.rs @@ -263,7 +263,7 @@ async fn verify_api_key(state: &AuthState, rest: &str) -> Result v, Err(err) => { tracing::error!(?err, "api_keys lookup failed"); @@ -271,6 +271,23 @@ async fn verify_api_key(state: &AuthState, rest: &str) -> Result MAX_API_KEY_CANDIDATES { + tracing::warn!( + prefix, + total = candidates.len(), + kept = MAX_API_KEY_CANDIDATES, + "api_keys prefix-bucket overflow; truncating candidate verify set" + ); + candidates.truncate(MAX_API_KEY_CANDIDATES); + } + // F-P-002: Argon2id verify is CPU-bound (~tens of ms each at OWASP // defaults). Move it off the Tokio async worker so a hot user with // N prefix-colliding keys doesn't park the worker for N×Argon2.