Finding
crates/exousia/src/api_key.rs compares a hashed API key against the stored hash using plain string equality (==) instead of a constant-time comparison, creating a timing side-channel on an authentication path.
Evidence
crates/exousia/src/api_key.rs:62: sha256_hex(long_token.as_bytes()) == stored_hash.
The same crate correctly uses argon2 with OsRng salt and does explicit issuer/audience validation on JWTs elsewhere (jwt.rs, password.rs), so the security discipline exists in this crate -- this one comparison just isn't held to it.
Why this matters
String equality short-circuits on the first mismatched byte, which leaks timing information proportional to how many leading bytes of the guess are correct. Exploitability here is low (the attacker would still need to defeat SHA-256 preimage resistance to turn timing leakage into a usable oracle), but it's exactly the pattern a security-focused lint or review is supposed to catch, and the fix costs nothing.
Desired correction
Replace the == comparison with a constant-time compare (e.g. the subtle crate's ConstantTimeEq, or ring/hmac-based fixed-time comparison already available in the dependency tree) for the hashed-key check at api_key.rs:62.
Done when: the API-key comparison at api_key.rs:62 uses a constant-time equality check, with a regression test asserting the comparison function used is the constant-time one (e.g. via a doc-test or a lint rule) rather than relying on review alone to keep it that way.
Finding
crates/exousia/src/api_key.rscompares a hashed API key against the stored hash using plain string equality (==) instead of a constant-time comparison, creating a timing side-channel on an authentication path.Evidence
crates/exousia/src/api_key.rs:62:sha256_hex(long_token.as_bytes()) == stored_hash.The same crate correctly uses argon2 with OsRng salt and does explicit issuer/audience validation on JWTs elsewhere (jwt.rs, password.rs), so the security discipline exists in this crate -- this one comparison just isn't held to it.
Why this matters
String equality short-circuits on the first mismatched byte, which leaks timing information proportional to how many leading bytes of the guess are correct. Exploitability here is low (the attacker would still need to defeat SHA-256 preimage resistance to turn timing leakage into a usable oracle), but it's exactly the pattern a security-focused lint or review is supposed to catch, and the fix costs nothing.
Desired correction
Replace the
==comparison with a constant-time compare (e.g. thesubtlecrate'sConstantTimeEq, orring/hmac-based fixed-time comparison already available in the dependency tree) for the hashed-key check atapi_key.rs:62.Done when: the API-key comparison at
api_key.rs:62uses a constant-time equality check, with a regression test asserting the comparison function used is the constant-time one (e.g. via a doc-test or a lint rule) rather than relying on review alone to keep it that way.