# Replayable one-time offer redemption

Accept/claim/redeem endpoints for one-time offers that never record consumption or check current state

_Area: Web business logic and race conditions. Seen in 3 disclosed reports; 2 confirmed bounties: $2,500 and $5,000; latest 2023-02-25. Updated 2026-10-23._

## How it works
A one-time benefit (fee discount, role promotion, invite) is granted by an endpoint that applies the benefit on every call but never records that the offer was consumed. The assumption "this offer ID is single-use" lives only in the UI or the intent of the flow, not in server state. Any client that can call the endpoint again gets the benefit again, sequentially, with no race needed. A related shape: the offer stays valid after the state that justified it is revoked, so acceptance is not tied to current authorization.

## Where it shows up
- State-changing endpoints named accept/claim/redeem/apply tied to an offer, coupon, or promotion ID.
- No redemption/consumption table, no idempotency key, no unique constraint checked before applying the benefit.
- Offer acceptance not re-checked against current role/status (e.g. after demotion or removal).
- Reward-on-leave or fast-track re-invite logic that ignores how the user originally joined.
- Grep for accept/claim/redeem handlers and confirm each has a consumption record.

## How to review
Find the endpoint that grants the benefit and confirm the invariant: each offer ID maps to at most one successful redemption per identity, recorded server-side atomically with the grant (e.g. a unique constraint on offer_id+user, insert-or-fail before the benefit applies). A second call with the same ID must be rejected or a no-op. Replay the accept call sequentially first; a race is not required. For role/promotion offers, confirm acceptance re-checks the requester's current authorization state, not just the offer's existence. For invite loops, confirm the reward path is gated on the original entry path.

## Variants seen
- Replaying a fee-discount accept endpoint to stack discounts from one offer ID [E1](https://bugbountylibrary.com/r/h1%3A1849626.md).
- Promotion offerId never invalidated after acceptance or demotion, so accept mutation replays to regain a revoked role [E3](https://bugbountylibrary.com/r/h1%3A1656380.md).
- Logic loop: leaving a program after a forwarded invite triggers a fresh fast-tracked invite, farming unlimited invites [E2](https://bugbountylibrary.com/r/h1%3A334205.md).

## Impact and severity
High: E1 stacked $600k of fee-free processing from a single $20k offer; E3 let a demoted user regain speaker/host role; E2 farmed unlimited private invites. Severity rises when the benefit is monetary, the endpoint is cheap to replay, and no consumption record exists to detect abuse after the fact.

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A1849626.md
- E2: https://bugbountylibrary.com/r/h1%3A334205.md
- E3: https://bugbountylibrary.com/r/h1%3A1656380.md
