The public discount-quote endpoint is rate-limited, fail-open
Context
The discount quote endpoint is public and unauthenticated: checkout calls it to tell a buyer whether a code is valid and what it is worth. That same shape lets an attacker brute-force code strings to discover a merchant's live codes and then redeem them, so the endpoint needs a throttle.
The platform already has a Redis fixed-window limiter pattern (e.g. KYC link minting), but that one fails closed — when Redis is unreachable it declines the action — because minting a credential is sensitive enough to prefer refusal over risk.
Decision
Rate-limit the public discount quote per (IP, merchant) using the same Redis fixed-window pattern, but fail open: if Redis is unreachable, allow the quote.
The reasoning is the inverse of KYC. A quote grants nothing — the money-authoritative checks all run again at order-create — so the cost of a Redis blip declining every quote (a broken checkout discount box for real customers) outweighs the marginal enumeration risk during that blip.
Consequences
- Positive: brute-force enumeration is blunted in normal operation, with no new dependency.
- Positive: a Redis outage degrades to "no throttle" rather than "no discounts," keeping checkout working.
- Neutral / to revisit: this mirrors the pre-existing unauthenticated fees endpoint, so it is not a new class of exposure; a fuller posture would throttle all public merchant routes (follow-up). The fixed-window mechanic now has a few hand-rolled copies worth consolidating into one shared limiter.
Alternatives considered
- Fail closed (like KYC): rejected — a Redis hiccup would break the checkout discount box for legitimate buyers, and a quote is not a credential.
- No rate limit (rely on order-create enforcement): rejected — it leaves code enumeration wide open on a public endpoint.