Skip to content

Build1 publisher3 min readPublished

A path-only cache bypass lets Cloudflare serve one shopper's cart header to another

Cloudflare caches by file extension and leaves HTML alone by default, so the exposure starts with the rule someone writes to lift the hit ratio. A dev.to write-up argues that rule has to match session cookies as well as paths.

The Engineer · Build desk

Illustration accompanying A path-only cache bypass lets Cloudflare serve one shopper's cart header to another

What happened

  • Cloudflare's documented default caches static assets matched by file extension and does not cache HTML, so a dynamic WordPress page stays out of the shared edge cache until a rule overrides that default.
  • Bypass rules that match only on URL path miss the personalization signal, because WooCommerce and other session-aware plugins mark a response with cookies such as woocommerce_cart_hash regardless of the URL.
  • It describes a second pattern, the zone-level cache-everything rule added to lift a low hit ratio, which can sweep in /wp-json/ and /wp-admin/admin-ajax.php.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • exposure The person exposed is a visitor with an empty basket: once HTML is cacheable and the rule ignores cookies, the edge can hand them a header rendered for someone else's session.
  • constraint A bypass expression is only correct for the plugin set that existed when it was written, so installing a plugin that adds a dynamic endpoint becomes a cache-rule edit that no release checklist prompts.
  • cost The safer expression spends a plan-limited budget of rules and characters, so on a small plan the fix has to be paid for before it fits.
  • decision Anyone chasing hit ratio on a WooCommerce zone has to choose the unit of bypass, and the zone-wide cache-everything shortcut answers it by caching the REST and admin-ajax paths too.

HTML stays out of Cloudflare's edge cache by default because HTML is not on the extension list Cloudflare caches from. Images, CSS and JS are [1]. On a WordPress install, that default keeps the two apart, because nearly every page resolves through index.php whether it is a product listing or a checkout [4]. Write a rule that makes HTML cacheable and the rule inherits the job of telling a public response from a personalized one, according to the dev.to post [2].

The rule most people write matches a path. An expression like `http.request.uri.path contains "/cart"` catches the obvious checkout flow [5]. It does not catch a product page whose header renders "3 items in cart", because what makes that response personal is a cookie, and WooCommerce and other session-aware plugins set `woocommerce_cart_hash` and `wp_woocommerce_session_` regardless of which URL was requested [6]. If the cached copy of that page is handed to the next visitor, they get the first visitor's cart state [7].

The expression the post recommends ORs six conditions: three paths, for /cart, /checkout and /my-account, and three cookie tests, for `woocommerce_cart_hash`, `wp_woocommerce_session_` and `wordpress_logged_in_`, with the rule's cache eligibility set to Bypass cache [8][15].

The snippet still needs work before it transfers to your zone. The cookie names have to match the ones the site actually sets. Exact names depend on plugin versions and prefix customization, the post says, so it tells you to confirm them in browser devtools instead of copying a list [9]. The expression also has to fit, because the number of Cache Rules per zone and the maximum expression length are plan-dependent [10].

The same pressure to lift a low hit ratio produces the other failure the post describes: a broad zone-level "cache everything" rule that sweeps in /wp-json/ and /wp-admin/admin-ajax.php [11]. Those are the paths a WordPress front end uses for responses meant to be generated per request [11].

On the evidence, this is a design argument rather than an incident report. The post calls it a commonly reported misconfiguration that often surfaces after someone widens caching and then trusts the cache more than the rules justify, and describes a setup-era rule left unrevisited as a plausible origin for the symptoms it lists [14]. It does not name an affected site or give an incidence rate. The symptoms it does list are specific: wrong cart contents served to different visitors, and an admin dashboard that flashes a cached homepage instead of the login form [16].

What a rule bypasses is whatever its expression matches. The post points at Cloudflare's Cache Rules documentation as the authoritative reference for expression syntax and precedence [12]. Legacy Page Rules are deprecated for new configuration, Cache Rules are the current way to do it, and running both at once makes precedence harder to reason about [13].

What to watch

  • Whether the Cache Rules limits published for your plan allow a six-condition expression plus the paths each new plugin adds.
  • Cookie prefixes confirmed in devtools after a WooCommerce or membership plugin update, since the recommended names depend on plugin version.
  • Zones still running legacy Page Rules alongside Cache Rules, where precedence decides which rule wins on a dynamic path.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories