[992] CORS Configuration Validation and Dynamic Origin Allowlist - #304
Conversation
Introduce cougr_core::cors, a no_std policy layer for HTTP gateways in front of game contracts: - CorsConfig validates origins, methods, header names, and max age, rejecting unsafe combinations such as credentials plus wildcard origin/method/header values - OriginAllowlist is runtime-mutable with exact origins, single-label wildcard subdomain patterns (https://*.example.com), and a global '*' entry; matching normalizes scheme/host case and default ports - evaluate_preflight returns ready-to-emit response headers or the canonical denied decision Covered by in-module unit tests and tests/integration_cors.rs.
|
Note for maintainers: the Core CI and Cougr Site workflow runs for this fork PR are in All CI steps were verified locally against the head commit (
|
salazarsebas
left a comment
There was a problem hiding this comment.
Excellent test coverage and careful spec-following on origin parsing (default ports, IPv6, wildcard subdomains). One design gap that matters given what this module is for:
evaluate_preflight() and response_allow_origin() never call validate() internally. If a caller sets allow_credentials = true with a wildcard "*" origin and calls either method directly (e.g. after mutating the allowlist at runtime post-startup, without re-validating), origins.allows(origin) returns true for any arbitrary origin because AllowEntry::Any matches everything, and the response echoes that attacker-controlled origin back with Access-Control-Allow-Credentials: true. That's precisely the origin+credentials leak this crate exists to prevent, and every test in the suite avoids it by always calling .validate() first.
Given this is meant to be the safety layer other gateway code trusts, I'd rather not ship it with a footgun that quiet. Two options: have evaluate_preflight/response_allow_origin call self.validate() internally and deny-by-default on failure, or introduce a Validated<CorsConfig> wrapper that's the only type those methods accept, constructible only via validate(). Happy to merge once one of those lands.
|
Hey @ToryMic , what are the updates on this pull request? |
evaluate_preflight and response_allow_origin now call validate() internally and deny-by-default when the policy is unsafe, closing the credentials + wildcard origin leak if callers skip validation or mutate the allowlist at runtime. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@salazarsebas I Addressed the review feedback in 17066d7 — went with internal re-validation rather than a What changed
This closes the footgun where Tests added (3 unit + 2 integration) covering:
Verified locally: |
salazarsebas
left a comment
There was a problem hiding this comment.
Re-validation fix confirmed — evaluate_preflight() and response_allow_origin() now call validate() and deny by default on failure, closing the credentials+wildcard gap. CI green on 17066d7. Approving.
Closes #299
Closes 992
Summary
Adds
cougr_core::cors, a dependency-free,no_std-compatible CORS policy layer for HTTP gateways (indexers, session servers, leaderboard APIs) that sit in front of Cougr game contracts.What's included
Configuration validation (
CorsConfig::validate)http/httpsschemes only; rejects paths, queries, fragments, userinfo, whitespace, invalid hosts/labels, and invalid ports (non-numeric,0, out of range, leading zeros)allow_credentials = truetogether with a wildcard (*) origin, method, or header — the combination browsers refuseMAX_ALLOWED_MAX_AGE_SECONDSDynamic origin allowlist (
OriginAllowlist)add/remove/cleartake effect immediately on live policieshttps://*.example.commatchesapi.example.combut nota.b.example.comor the apex), and global*http://host:80≡http://host)Request evaluation
evaluate_preflightreturns aPreflightDecisioncarrying ready-to-emitAccess-Control-*header values (echoed origin vs.*, granted headers incl. safelisted ones) or the canonical denied decisionresponse_allow_originmirrors the same rules for actual (non-preflight) responsesTesting
tests/integration_cors.rs)cargo fmt --check,cargo clippy --all-targets --all-features -- -D warnings,cargo test --workspace --features testutils,cargo build, andcougr checkhygiene pass