fix(limit-count): validate variable-resolved count/time_window bounds#13573
Conversation
count and time_window may be set from request variables (e.g.
"${http_count}"). The resolved value was only coerced with tonumber,
so a client could supply 0, a negative, a fractional, or an out-of-range
value, which slipped past the schema's >0 integer bounds and hit the
limiter constructor's assert (500) or skewed the limit.
Validate the resolved value the same way limit-conn already does:
positive, integer, within safe integer range.
…error Address review: use a generic error message instead of echoing the raw resolved value (request-derived), clarify TEST 9 as route setup, and add TEST 11 exercising out-of-bounds time_window rejection.
|
This looks incomplete for The new As a result, when Could we return the validation error for |
In rules mode get_rules() swallowed resolve_var errors via goto CONTINUE, so a client-controlled variable resolving to an invalid count/time_window silently dropped the rule instead of rejecting the request, bypassing the limit. Return the error for count/time_window; only skip a rule when its key does not resolve. Add a rules-mode regression test.
|
Good catch, you're right. In Fixed: |
…e_window A rule whose key resolves to nothing must be skipped before its count/ time_window are validated, otherwise a rule meant not to apply (its count/time_window vars also absent) wrongly rejects the whole request.
Description
limit-countletscountandtime_windowbe set from a request variable, e.g."count": "${http_count ?? 2}". At request time the resolved string was only coerced withtonumberand checked for being a number. It was never bounds-checked, so a client-supplied value of0, a negative, a fractional, or an out-of-range number bypassed the schema's> 0integer constraint:0/negative hit the limiter constructor'sassert(limit > 0 and window > 0), turning a client header into a request-time error.This mirrors the validation
limit-connalready performs on its variable-resolvedconn/burst: the resolved value must be a positive integer within the safe integer range (2^53-1). Invalid values are now rejected through the normal error path instead of reaching the limiter.limit-conn's identical gap was already fixed; this closes the same hole inlimit-count.Which issue(s) this PR fixes:
N/A (hardening; reported internally against the API7 fork)
Compatibility
No valid configuration changes behavior: a request variable that resolves to a positive integer is handled exactly as before. There is one observable change at the out-of-spec edge:
0/negative resolved values already errored at request time (via the limiter'sassert); they now error through the normal path with a clearer message. Same client-visible outcome.>2^53-1) resolved values were previously accepted and served with skewed limiting math; they are now rejected (rejected_code/500). These values were never valid per the schema (integer,> 0) and produced incorrect limiting, so this is the correct behavior, but a client that was unknowingly sending such values and getting served will now be rejected.count/time_windowresolved to an invalid value was silently skipped (goto CONTINUE), bypassing that rule's limit; it now rejects the request, the same as the non-rules path. A rule whose key does not resolve is still skipped, since such a rule legitimately does not apply to the request.Checklist
> 0; behavior now matches)