OWASP Automated Threat OAT-021 | Part 5 of 10
A product sells out on your site in under a minute. Your merchandising team celebrates. Your ops team scrambles to update the page. Forty-eight hours later, the inventory is still sitting in carts that will never check out, the product shows as unavailable to real customers, and nobody on the security team has connected the dots.
That's OWASP OAT-021 Denial of Inventory, also known as inventory hoarding, seat spinning, or the hold-all attack. Bots systematically add items to carts or reserve seats without ever completing the transaction, holding your stock hostage in the gap between "added to cart" and "purchased." The tools most teams rely on to catch it have no framework for recognizing what's happening.
What is OAT-021 Denial of Inventory?
Denial of Inventory is an automated abuse of your application's reservation and cart-holding logic. Bots systematically add items to carts, reserve seats, hold appointment slots, or claim allocation without ever completing the transaction. The goods never get bought. The attacker never pays. But for the duration of the hold, that inventory is unavailable to anyone else.
The attacker doesn't need a credential. They don't need a vulnerability. They just need to interact with the same functionality your legitimate customers use, at machine speed, in volume. Your application is doing exactly what it was designed to do: honoring a cart reservation, holding a seat for a few minutes so a real user can finish entering payment details, keeping an appointment slot open while someone clicks through a booking flow. The bot uses that intended behavior as a weapon.
The surface area is broader than most teams realize. E-commerce carts are the obvious case: an attacker adds hundreds of limited-edition sneakers to baskets across thousands of sessions and lets the reservations time out. But the same pattern applies to hotel room bookings, restaurant reservations, concert seats, flight selections, click-and-collect pickups, appointment slots for healthcare or services, queue positions for product drops, and budget allocations in programs with fixed pools. Anywhere your application treats a resource as temporarily held while a user completes a workflow, you have a denial of inventory surface.
The motivations vary. Competitors run inventory hoarding campaigns to make your products look unavailable and push customers to substitute alternatives. Resellers use it as a staging tactic adjacent to scalping, holding inventory off the market while coordinating demand. Coordinated harassment campaigns target booking platforms to disrupt specific businesses. Sometimes the attacker just wants to cause damage, and your inventory is the lever. OWASP specifically distinguishes denial of inventory from scalping because the attacker isn't trying to acquire the goods. They're trying to prevent anyone else from acquiring them.
The business impact compounds quietly. Bad bot traffic now accounts for at least 37% of all automated web traffic, with commerce and travel disproportionately targeted. Direct revenue loss stacks up from legitimate customers who hit "out of stock" and leave. Cart abandonment rates rise in ways that poison your conversion metrics and ad spend attribution. Your merchandising team sees sell-through that doesn't match fulfillment. Customer service gets escalations from confused buyers who watched a product show as available, then unavailable, then available again an hour later. In industries with regulated inventory, like appointment slots for public services or regulated booking platforms, the attack creates demonstrable access inequities that carry compliance exposure.
Unlike denial of service, there's no resource exhaustion on your infrastructure. Your servers are fine. Your application is responding normally. From every metric your SRE team watches, the system is healthy. The damage is entirely in the business layer, which is precisely the layer most security tooling doesn't observe.
How does Denial of Inventory move through the stack?
Understanding why this attack evades traditional controls requires following it through the actual request path.

The attacker's bot makes a POST request to your add-to-cart endpoint, reservation API, or booking submission handler. The request is structurally identical to what a real customer sends. Valid product SKU. Plausible quantity. A session token that was created moments earlier through a legitimate-looking browse sequence. HTTP headers that mimic a mobile browser. The IP address routes through a residential proxy pool and resolves to a consumer ISP in a reasonable geographic region. There is nothing about the request, considered on its own, that distinguishes it from a shopper on their phone.
The request reaches your WAF. The WAF inspects it. There's no injection payload. No malformed header. No signature match. The request body is well-formed. The endpoint is a normal commerce endpoint that receives thousands of legitimate calls per hour. The WAF passes it through.
The request reaches your application layer. Your application does what it's supposed to do: decrements available inventory, creates a cart record, sets a reservation timeout (typically 10 to 30 minutes, sometimes hours for booking platforms), and returns a success response. The bot logs the cart ID and moves on. It does not proceed to checkout. It does not submit payment. It does not abandon the session in any way the application recognizes as abandonment, because the reservation window hasn't expired yet.
The bot repeats the pattern across thousands of sessions, rotating IPs, rotating user-agents, rotating session tokens, spacing requests to stay below any per-source velocity threshold. Each request, in isolation, looks like a customer considering a purchase.
The meaningful signal only exists in aggregate, across time, at the application layer. It looks like this: add-to-cart volume is four times the historical baseline, while checkout conversion on the same SKUs has collapsed toward zero. Session durations are unusually short and structurally uniform. The ratio of add-to-cart events to product-detail page views is wildly inverted. Cart abandonment timing clusters at exactly the reservation timeout, then new reservations refill the same inventory moments later. None of this is visible at the network perimeter. All of it is visible in the request and response data flowing through the application.
Worse, the attack is specifically designed to hide in normal commerce patterns. Real customers abandon carts all the time. Real customers browse without buying. Real traffic spikes during product launches. A bot that adds items to carts is not doing anything that a human shopper doesn't also do. The difference is velocity, coordination, and the absolute collapse of the purchase funnel downstream, and those are signals that require visibility across the entire request path, correlated over time.
What happens when a Denial of Inventory alert fires?
Assume something eventually surfaces. Maybe your merchandising team flags an anomalous sellout pattern. Maybe a fraud analyst notices that cart creation is decoupling from revenue. Maybe a customer service escalation traces back to inventory that keeps flickering in and out of availability. An alert fires, or at least a question gets asked.

Your WAF doesn't have the context to respond. The WAF never saw the problem in the first place, because the problem isn't in any individual request. It's in the relationship between add-to-cart events, checkout events, session behavior, and reservation timeouts. That relationship only exists at the application layer. Writing a WAF rule to stop this attack would require encoding business logic the WAF has no visibility into: "block requests from sessions whose add-to-cart-to-checkout ratio exceeds X over Y minutes, weighted by session age and product SKU sensitivity." That rule doesn't exist in any WAF product.
So the response becomes manual. Even with AI assistants compressing log correlation from days to minutes, someone still has to decide what the attack actually is, pull the application logs, pull the cart abandonment data, join the session analytics, and figure out which sessions added inventory and never returned. The investigation is faster than it used to be. The enforcement path isn't. Meanwhile, carts continue to fill and time out. New reservations replace the old ones. The attack pattern persists through the investigation because identifying it faster doesn't mean you can stop it faster.
When the team finally identifies candidate indicators, the question becomes what to do with them. Blocking at the WAF requires specific attributes like IP ranges, ASN, user-agent patterns. The attacker rotates those faster than your change control process can deploy rules. Blocking at the application requires code changes, typically to cart logic, which is revenue-critical code that nobody wants to modify under pressure. Shortening the reservation window hurts legitimate customers with slow connections or interrupted checkouts. Adding CAPTCHAs to the add-to-cart flow tanks conversion. Every available lever has a cost, and the cost lands on the business before it lands on the attacker.
The enforcement gap is especially punishing here because the attack is ongoing while you investigate it. Card cracking gives you chargebacks you can trace back later. Denial of inventory gives you a slow bleed of abandoned sessions and lost conversions that may never be cleanly attributable. The attack ends when the attacker decides it ends. Your visibility into whether it's still happening is structurally incomplete.
There's also a detection fatigue problem specific to this threat. Because the symptoms overlap with legitimate commerce patterns (sellouts, abandoned carts, traffic spikes), teams habituate to the noise. By the time the pattern is obviously abnormal, weeks of inventory holds have already shaped customer behavior, ad spend, and replenishment decisions. You're responding to an attack that already finished shaping your business.
What we see when detection and enforcement share a request path
The core problem with WAF-based approaches to denial of inventory isn't rule quality. It's that the attack is not a request problem. It's a behavioral problem that only exists in the relationship between requests and the application's response to them over time. A WAF sitting outside the application can't see that relationship. It can't see which sessions completed purchases and which didn't. It can't correlate add-to-cart volume against checkout conversion by SKU. It can't watch reservation timeouts roll over and refill with new bot traffic. That signal lives inside the request path.
Impart operates inside the application's request path. For denial of inventory, this changes what's possible in specific ways.

First, Impart observes the full transaction lifecycle, not just individual requests. When a session adds items to a cart, Impart sees it. When that session does or doesn't proceed to checkout, Impart sees that too. When add-to-cart volume across a population of sessions decouples from checkout volume, Impart sees the pattern forming in real time, not in a post-hoc log review after the inventory has already been held for a week. The behavioral telemetry that makes denial of inventory detectable, session-level cart-to-purchase ratios, reservation timeout patterns, SKU-level anomalies against historical baselines, is exactly what Impart is built to observe because it's watching from inside the application.
Second, Impart enforces in the same place it detects. When the signal is clear, Impart can act: challenge the next suspicious add-to-cart, rate-limit a session that's accumulating reservations without progressing, release inventory held by sessions exhibiting bot-characteristic behavior, or return a response that holds the reservation nominally while quietly excluding it from true availability calculations. That enforcement happens inline, on the next request, without a ticket to a WAF admin or a change control process.
Shadow mode matters more for denial of inventory than almost any other OWASP automated threat, because the risk asymmetry at the cart is severe. False positives here aren't abstract. A rule that wrongly flags a legitimate shopper's add-to-cart action is a rule that directly costs revenue, and the business will notice. Impart deploys first in observational mode, watching real customer and bot traffic against your real commerce flow, and builds decision evidence before enforcement goes live. Security teams can review exactly which sessions Impart would have intervened on, validate the signal against actual customer outcomes, and turn enforcement on only when the evidence supports it. You don't guess at what a rule will do to conversion. You see it first.
The enforcement surface also extends beyond what a WAF can express. Impart can target attacker behavior by session fingerprint, cart-to-checkout ratio, reservation velocity, SKU-level targeting patterns, or any other attribute visible in the request path. When attackers rotate IPs and user-agents, those behavioral attributes often persist, and enforcement can follow them.
Denial of inventory is a pure abuse-of-functionality attack. The application isn't broken. The code isn't vulnerable. Your reservation logic is doing exactly what you designed it to do. The attacker is using that correct behavior, at scale, to deny availability to everyone else. Traditional security tooling has no model for "legitimate functionality being used at machine speed to consume a finite resource without paying for it." Impart does. That's the difference between a security tool that inspects your requests and one that understands what your application is doing with them.
See what you would block before you block it
Impart closes the enforcement gap for denial of inventory and all 21 OWASP automated threats. Shadow mode against live traffic. Full decision evidence. Enforcement when you're ready.
OWASP Deep Dive Series
This post is part of a 10-part series examining how OWASP automated threats expose the gap between detection and enforcement, and what changes when both move into the application's request path.