Summary
A resolved-but-empty master API key is treated as a valid key: any request carrying an empty X-API-Key header authenticates as master (full cross-tenant read access). Empty should mean "not configured", not "the valid key".
Evidence
crates/vym-fyi-server-crud/src/app.rs:214-222 — the master binding is registered from master_api_key with no empty check.
crates/vym-fyi-server-crud/src/app.rs:36-47 — constant_time_eq("", "") returns true (the loop over max = 0 leaves diff == 0).
crates/vym-fyi-server-crud/src/auth.rs:30-34 — an empty X-API-Key: header parses as Some(""), not None.
Exploitation scenario
- An operator follows the shipped pattern
master_api_key: "$(MASTER_API_KEY)" (documented in charts/vym-fyi-server-crud/values.yaml:119-124) while MASTER_API_KEY is set to the empty string (the chart default at values.yaml:51).
- Attacker sends
GET /api/links with X-API-Key: <empty>.
authenticate matches the master binding (is_master: true, tenant_id: None) → the attacker can list every tenant's links (links.rs:184-185 uses WHERE TRUE for master).
Severity: HIGH — authentication bypass footgun in the security-critical path, reachable via a config state the repo itself advertises.
Suggested fix
- In
build_api_key_bindings (app.rs:195-225): skip or hard-error on empty resolved keys (fail-closed).
- In
ApiKeyStore::authenticate (app.rs:35-69): reject an empty api_key outright.
Summary
A resolved-but-empty master API key is treated as a valid key: any request carrying an empty
X-API-Keyheader authenticates as master (full cross-tenant read access). Empty should mean "not configured", not "the valid key".Evidence
crates/vym-fyi-server-crud/src/app.rs:214-222— the master binding is registered frommaster_api_keywith no empty check.crates/vym-fyi-server-crud/src/app.rs:36-47—constant_time_eq("", "")returnstrue(the loop overmax = 0leavesdiff == 0).crates/vym-fyi-server-crud/src/auth.rs:30-34— an emptyX-API-Key:header parses asSome(""), notNone.Exploitation scenario
master_api_key: "$(MASTER_API_KEY)"(documented incharts/vym-fyi-server-crud/values.yaml:119-124) whileMASTER_API_KEYis set to the empty string (the chart default atvalues.yaml:51).GET /api/linkswithX-API-Key: <empty>.authenticatematches the master binding (is_master: true,tenant_id: None) → the attacker can list every tenant's links (links.rs:184-185usesWHERE TRUEfor master).Severity: HIGH — authentication bypass footgun in the security-critical path, reachable via a config state the repo itself advertises.
Suggested fix
build_api_key_bindings(app.rs:195-225): skip or hard-error on empty resolved keys (fail-closed).ApiKeyStore::authenticate(app.rs:35-69): reject an emptyapi_keyoutright.