security: enforce nonce-store hard cap to bound memory under unique-id bursts#19
Merged
Conversation
…ECURE F7 from the 2026-05-26 CSO review: serving /execute and /audit/export over plain HTTP on a non-loopback address exposes containment commands and tenant audit history in cleartext (signed for integrity, not encrypted). The proxy now refuses to start in that case unless ALLOW_INSECURE=true is set explicitly, matching the safe-by-default posture of DRY_RUN. A warning was not enough to stop a misconfigured deploy from serving cleartext to the internet. Validation: cargo fmt --check + clippy -D warnings clean, 19 tests pass.
claim_or_replay ran only TTL-based eviction (evict_expired) at the cap, so a burst of more than MAX_RECORDS unique request_ids inside the RETENTION window left every record younger than the cutoff, freed nothing, and grew the map without bound (OOM). The MAX_RECORDS comment promised a hard cap that did not exist. evict_to_cap now drops the oldest entries down to 90% of the cap when TTL eviction is insufficient. Keys are collected before removal so no DashMap iteration and write guard overlap. Regression test inserts MAX_RECORDS+1000 unique fresh claims and asserts len() stays <= MAX_RECORDS.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Item 4 of the pre-launch hardening punch list (proxy side).
Problem
NonceStore::claim_or_replayonly ran TTL-based eviction (evict_expired) when at the cap. A burst of more thanMAX_RECORDS(100k) uniquerequest_ids inside theRETENTION_SECONDS(600s) window leaves every record younger than the cutoff, soevict_expiredfrees nothing and theDashMapgrows without bound — OOM. TheMAX_RECORDSdoc comment claimed a hard cap ("evict the oldest entries to make room") that the code never implemented.Authenticated path (valid HMAC + 30s replay window gate it), so not an open-internet DoS — but the bounded-memory guarantee the comment promises was false.
Fix
evict_to_capdrops the oldest entries down to 90% of the cap when TTL eviction leaves the map still at/aboveMAX_RECORDS. Keys are collected (iterator fully drained) before removal, so noDashMapiteration guard overlaps a write guard.Test
unique_id_burst_is_bounded_by_hard_capinsertsMAX_RECORDS + 1000unique fresh claims and assertslen() <= MAX_RECORDS.Validation
cargo test nonce— 7 passed (incl. new test)cargo clippy -- -D warnings— cleancargo fmt --check— clean