Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Detection rules for WooCommerce facet/cart flood DDoS campaign #4623

Copy link
Copy link
@wadejbeckett

Description

@wadejbeckett
Issue body actions

Description

Reporting a false negative: CRS (tested at PL1 and PL2) does not detect a
distributed botnet DDoS campaign currently active against WooCommerce
stores. The campaign uses GET-based cart and facet parameter flooding to
saturate PHP-FPM pools via forced uncached WP_Query execution.

Two distinct request patterns are used in rotation:

Pattern A — GET add-to-cart flood: bot sends GET requests with
add-to-cart=<product_id> in the query string. Legitimate WooCommerce
themes use POST/AJAX for cart operations; GET add-to-cart at volume is
essentially always malicious.

Pattern B — Facet parameter permutation flood: bot enumerates
combinations of facet parameters (product_count, product_orderby,
product_order, product_view, orderby, per_page, min_price,
max_price, filter_*) on WooCommerce taxonomy and listing paths
(/product-tag/, /product-category/, /category/, /shop/,
/products/, /collections/, /tag/). Each permutation defeats caching
and forces a fresh WP_Query execution.

Botnet characteristics observed:

  • Thousands of unique residential source IPs per wave
  • 1–3 requests per source IP (defeats per-IP rate limiting)
  • Spoofed Chrome/Safari/Edge User-Agents
  • No session cookies, no Referer on most requests
  • Targets appear to be discovered by enumeration of shared hosting IPs
    (two separate sites on the same server hit in sequence weeks apart)

Observed impact on an unprotected WooCommerce site with a 10-worker
PHP-FPM pool: full saturation within approximately 30 seconds; cascading
504 Gateway Timeout errors; neighbouring vhosts starved via Apache
MaxRequestWorkers exhaustion; load average rising from baseline 2 to 17+;
sustained outage until mitigation deployed.

After deploying custom rules (shown below) on ModSec 2.9 running CRS at
PL1, over 95% of attack requests were blocked at phase:1. Load recovered
within minutes, with zero reported false positives on legitimate customer
traffic during initial monitoring.

How to reproduce the misbehavior (-> curl call)

Each of the following requests represents in-the-wild attack traffic that
passes CRS PL1 and PL2 without triggering a block:

# Pattern A — GET add-to-cart
curl -i "https://target.example/products/item-slug/?add-to-cart=1234"
curl -i "https://target.example/category/gloves/?add-to-cart=2614&product_count=60"
curl -i "https://target.example/product-tag/safety/?add-to-cart=3371&product_order=desc"

# Pattern B — facet permutation on taxonomy paths
curl -i "https://target.example/product-tag/safety/?product_count=40&product_orderby=name"
curl -i "https://target.example/category/gloves/?product_view=list&product_order=desc"
curl -i "https://target.example/shop/?orderby=price&per_page=60"
curl -i "https://target.example/product-category/footwear/?filter_size=large&min_price=100"

# Pattern C (related variant) — GET to wc-ajax endpoints
curl -i "https://target.example/?wc-ajax=add_to_cart"
curl -i "https://target.example/?wc-ajax=get_refreshed_fragments"

Expected behaviour: CRS should flag these as suspicious GET abuse against
WooCommerce endpoints, given that all of these operations are documented
as POST/AJAX in WooCommerce core.

Actual behaviour: all requests pass through CRS without matching any
existing rule.

Logs

Anonymised access log samples from a real attack wave (IPs scrubbed,
domain replaced, timestamps preserved for rate indication):

X.X.X.X - - [23/Apr/2026:14:02:17 +0200] "GET /product-tag/construction/?product_count=40&product_view=list HTTP/1.0" 504 3781 "https://target.example/product-tag/construction/?product_count=40" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
X.X.X.X - - [23/Apr/2026:14:02:17 +0200] "GET /category/gloves/?add-to-cart=2654&product_count=60&product_order=asc&product_orderby=date&product_view=list HTTP/1.0" 504 3781 "https://target.example/category/gloves/?add-to-cart=2654&product_count=60&product_orderby=date&product_view=list" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"
X.X.X.X - - [23/Apr/2026:14:02:18 +0200] "GET /product-tag/ppe/?add-to-cart=3992&product_count=60&product_orderby=popularity HTTP/1.0" 504 3781 "https://target.example/product-tag/ppe/?add-to-cart=3992&product_count=60&product_orderby=price" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0"
X.X.X.X - - [23/Apr/2026:14:02:18 +0200] "GET /product-tag/safety/?add-to-cart=2881&product_count=20&product_orderby=price&product_view=grid HTTP/1.0" 504 3781 "https://target.example/product-tag/safety/?add-to-cart=2881&product_count=60&product_orderby=price&product_view=grid" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"

Full sanitised audit log export available on request — happy to share
privately with maintainers if useful.

Proposed detection

Phase 1 chain rules. Have been running in production for the past few
hours with no observed false positives:

SecRule REQUEST_METHOD "@streq GET" \
  "id:9xxxxx,phase:1,chain,block,t:none, \
   msg:'WooCommerce: Suspicious GET add-to-cart request', \
   tag:'application-multi',tag:'platform-woocommerce', \
   tag:'attack-dos',severity:'CRITICAL'"
  SecRule QUERY_STRING "@rx (?:^|&)add-to-cart=" ""

SecRule REQUEST_METHOD "@streq GET" \
  "id:9xxxxx,phase:1,chain,block,t:none, \
   msg:'WooCommerce: Facet parameter flood on taxonomy path', \
   tag:'application-multi',tag:'platform-woocommerce', \
   tag:'attack-dos',severity:'CRITICAL'"
  SecRule REQUEST_FILENAME \
    "@rx ^/(product-tag|product-category|category|shop|products|collections|tag)/" "chain"
  SecRule QUERY_STRING \
    "@rx (?:^|&)(product_count|product_orderby|product_order|product_view|orderby|per_page|min_price|max_price|filter_[a-z_]+)=" ""

SecRule REQUEST_METHOD "@streq GET" \
  "id:9xxxxx,phase:1,chain,block,t:none, \
   msg:'WooCommerce: GET to wc-ajax cart endpoint', \
   tag:'application-multi',tag:'platform-woocommerce', \
   tag:'attack-dos',severity:'CRITICAL'"
  SecRule QUERY_STRING \
    "@rx (?:^|&)wc-ajax=(add_to_cart|get_refreshed_fragments|remove_from_cart|apply_coupon)" ""

Suggest placement in a new REQUEST-94x-APPLICATION-SPECIFIC-WOOCOMMERCE.conf
file, or in REQUEST-934-APPLICATION-ATTACK-GENERIC.conf. Could also be
gated behind an opt-in variable like tx.enforce_woocommerce_hardening
given that the target audience is specifically WooCommerce hosts.

Your Environment

  • CRS version: 3.x (default paranoia level 1)
  • Paranoia level setting: PL1 (also tested at PL2 — same result)
  • ModSecurity version: 2.9
  • Web Server and version: Apache httpd 2.4 with mod_proxy_fcgi to PHP-FPM
  • Operating System and version: Ubuntu 24.04 LTS (Plesk-managed hosting)

Confirmation

[x] I have removed any personal data (email addresses, IP addresses,
passwords, domain names) from any logs posted.

Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.