diff --git a/backend/windmill-api-auth/src/auth.rs b/backend/windmill-api-auth/src/auth.rs index 6d96112ec5..d1d0295d4d 100644 --- a/backend/windmill-api-auth/src/auth.rs +++ b/backend/windmill-api-auth/src/auth.rs @@ -175,6 +175,13 @@ impl AuthCache { if is_no_auth() { return Some(OptJobAuthed { authed: no_auth_admin_authed(), job_id: None }); } + // Reject an oversized guest bearer before the cache key is built from it: the key + // copies and hashes the whole token, so the cap should bound that work too. + if token.starts_with(windmill_common::guest_jwt::BEARER_PREFIX) + && token.len() > windmill_common::guest_jwt::MAX_GUEST_JWT_LEN + { + return None; + } let key = ( w_id.as_ref().unwrap_or(&"".to_string()).to_string(), token.to_string(), @@ -222,12 +229,9 @@ impl AuthCache { let Some(w_id) = w_id.as_deref() else { return None; }; - // The cache keys on the whole bearer, so bound it here before verify or caching; - // strip exactly one prefix, or repeated prefixes would shrink an oversized - // bearer past the length check while it is still cached at full size. - if token.len() > windmill_common::guest_jwt::MAX_GUEST_JWT_LEN { - return None; - } + // Strip exactly one prefix: `trim_start_matches` would strip repeated prefixes, + // so `jwt_guest_jwt_guest_` would reduce to a valid token that verifies and + // is then cached under the full, non-canonical bearer key. let jwt = token .strip_prefix(windmill_common::guest_jwt::BEARER_PREFIX) .unwrap_or(token);