PrivacyForgeSign In
Back to Blog

When Your Cache Leaks Personal Data: A GDPR Guide

WooCommerce 11.1 patches a cache bug that could serve one shopper’s IP and session ID to the next visitor. Audit whether your own cache leaks personal data.

PFMariyan ValevAug 28, 2026 · 15 min read
GuideGuide

Key Takeaways

  • WooCommerce 11.1, due 1 September 2026, strips nine request-derived properties out of cacheable analytics output. Six are request headers — _via_ip, _via_ua, _via_ref, _dr, _dl, _lg — and three are session-cookie fields: session_id, landing_page, is_engaged. The page payload drops from 20 properties to 11, all of them store-level.
  • The mechanism is the lesson. Per the pull request, "neither headers nor cookies are in the CDN cache key", so "whichever request fills the cache decides what every later visitor reports as their own IP, UA, referrer — and session identifier."
  • Article 4(12) GDPR does not require an attacker. It defines a personal data breach as a breach of security leading to the "accidental or unlawful … unauthorised disclosure of, or access to, personal data" — accidental sits first in the list.
  • The EDPB says the same thing in its taxonomy. Guidelines 9/2022 (Version 2.0, adopted 28 March 2023), paragraph 17: a "Confidentiality breach" is "where there is an unauthorised or accidental disclosure of, or access to, personal data."
  • This class of incident breaks breach scoping. Article 33(3)(a) asks for the categories and approximate number of data subjects "where possible" — and when the cache has substituted the very identifiers you would use to count, that qualifier stops being boilerplate.

Introduction

Your store has no security advisory open, no suspicious logins, no ransom note. It also has a CDN in front of it, because everyone does, and its pages are fast because they are shared. That sharing is the point. It is also, on a bad day, the disclosure.

On 18 August 2026 WooCommerce published its 11.1 pre-release notes with a line that deserves more attention than a changelog usually gets: "Analytics page output no longer carries request-derived properties, so cached pages cannot emit another visitor's request data." No CVE, no advisory, no red banner. Just a fix, shipping 1 September 2026, for a failure mode most incident plans have no category for.

This article is informational content, not legal advice. For organisation-specific guidance, consult a qualified legal professional.

Is a Caching Misconfiguration a GDPR Personal Data Breach?

It can be, and the deciding word is "accidental". Article 4(12) GDPR defines a personal data breach as "a breach of security leading to the accidental or unlawful destruction, loss, alteration, unauthorised disclosure of, or access to, personal data transmitted, stored or otherwise processed." Nothing in that definition asks who caused it, or whether anyone meant to.

The EDPB's own taxonomy is equally explicit. Guidelines 9/2022 on personal data breach notification (Version 2.0, adopted 28 March 2023) sets out three categories at paragraph 17, drawing on WP29 Opinion 03/2014. The first is a "Confidentiality breach" — "where there is an unauthorised or accidental disclosure of, or access to, personal data." A cache that hands visitor B the identifiers belonging to visitor A is a textbook fit, and it never needed a villain.

That matters because the reflex runs the other way. Paragraph 15 of the same guidelines warns that "whilst all personal data breaches are security incidents, not all security incidents are necessarily personal data breaches" — usually read as a reason to downgrade an incident. It cuts both ways: some things that never looked like security incidents land squarely inside Article 4(12).

What WooCommerce 11.1 Actually Fixed

The change is pull request #67003, "Stop sending request-derived props into cacheable analytics page output", merged 27 July 2026 against the 11.1.0 milestone. It removes two groups of values from page output that could be cached: request headers (_via_ip, _via_ua, _via_ref, _dr, _dl, _lg) and session-cookie fields (session_id, landing_page, is_engaged).

The fix splits the old catch-all get_common_properties() into three: get_page_common_properties() for store-level values only, get_session_properties() for request-derived session data, and get_server_details(). The server-fired tracking path is left unchanged, which is the tell — the data was never the problem, its location was.

Two numbers show the size of the change. The page payload fell from 20 properties to 11, all store-level. Search pixel URLs shrank from roughly 4,006 characters to 2,435 in the scenarios the PR tested — those identifiers were travelling in query strings, which is exactly where they end up in logs.

Be precise about who was exposed. The affected code is the woocommerce-analytics package, and its README states the package "only starts tracking when: WooCommerce 3.0 or higher is active and installed, Jetpack is connected (Phase 1 requirement — will be decoupled in Phase 2), In site page context." So the population at risk is stores running WooCommerce Analytics with a Jetpack connection, behind a shared cache — not every WooCommerce store on the internet. WooCommerce has published no assessment of how many stores were affected, and no confirmed incident is on the public record. What exists is a mechanism that made disclosure possible.

Why the Cache Key Is the Whole Story

A cache key is the fingerprint a cache uses to decide "I have seen this request before." If two requests produce the same key, the second gets the first one's stored response. That is the entire value proposition of caching, and it is safe exactly as long as the response contains nothing the key does not account for.

Here the response contained the visitor's IP address, user-agent, referrer and session identifier. The key did not include them. The PR states the consequence without euphemism: because "neither headers nor cookies are in the CDN cache key", "whichever request fills the cache decides what every later visitor reports as their own IP, UA, referrer — and session identifier."

So the first shopper to warm a cached page donated their identifiers to everyone who arrived after it — served to them in the markup, and transmitted onward on their behalf. Recital 30 GDPR removes any argument about whether that is personal data: it names "internet protocol addresses, cookie identifiers" as online identifiers, and Article 4(1) lists "an online identifier" in the definition of personal data itself.

Our position, stated plainly: cache-key design is an Article 32 technical measure and should be documented as one. Article 32(1)(b) requires "the ability to ensure the ongoing confidentiality … of processing systems and services", and Article 32(1)(d) requires "a process for regularly testing, assessing and evaluating the effectiveness" of those measures. A cache key that does not vary on the personal data in the response is hard to defend as "the ability to ensure the ongoing confidentiality" of that service, and a store that has never tested for it has nothing to show against the second. Neither is a verdict — no regulator or court has ruled on cache-key design — but both are the kind of gap you would rather close than explain. The trade-off is worth naming — varying a key on cookies can collapse your hit rate. So the answer is not to vary the key but to keep per-visitor data out of the cached body, which is the route WooCommerce took.

Cache Poisoning, Cache Deception, and the Case With No Attacker

Search for cache-related data exposure and you get two well-documented attack techniques, neither of which is what happened here. All three columns below engage the EDPB's confidentiality limb — the first of the three categories at paragraph 17 of Guidelines 9/2022 — but only the third has no adversary in it. The distinction decides which playbook you reach for, and most teams own only the wrong two.

Cache poisoningCache deceptionMis-keyed cache (this case)
Attacker requiredYesYesNo
TriggerCrafted requestTricked victim URLOrdinary traffic
Who is exposedWhoever the attacker targetsThe tricked userEvery visitor, by default
DetectionAnomalous requestsAnomalous URL patternsNothing looks anomalous
GDPR limbConfidentiality / integrityConfidentialityConfidentiality (accidental)

The third column is the one with no literature behind it. Poisoning and deception both leave a shape in your logs — a strange header, an odd path — because someone had to do something unusual. A mis-keyed cache leaves nothing. Every request was legitimate; every response was served correctly, by a cache doing exactly what it was configured to do. The only irregularity sits in the body of a page nobody re-read.

That is why this failure mode survives security reviews. It is not hiding from your monitoring; it is invisible to it.

Were You Affected? A Five-Step Self-Assessment

You were exposed only if three things were true at once: WooCommerce Analytics was running, a shared cache sat in front of your storefront, and that cache did not vary on the cookies and headers the analytics payload carried. Work through the five steps below in order, and write each answer down.

  1. Establish scope first. Is WooCommerce Analytics actually running? Per the package README, it needs WooCommerce 3.0+ and, in Phase 1, a Jetpack connection. No connection, no tracking, no exposure from this particular bug. Record how you established it — "we think we were fine" is not an assessment.
  2. Identify every shared cache in the path. Not just the CDN — full-page cache plugins, a host-level edge cache, a reverse proxy inherited from a previous agency. Each is a place where one visitor's response can become another's.
  3. Check what those caches vary on. Look at the cache key configuration and whether Vary headers are honoured for storefront routes. A cache that ignores Vary is not misbehaving; it is doing what most default configurations do.
  4. Read the cached HTML, not the live HTML. Fetch a page as an anonymous visitor twice from different networks and diff the analytics payload. If the second response carries the first visitor's values, you have reproduced the mechanism on your own store.
  5. Check your version and plan the upgrade. The fix ships in 11.1 on 1 September 2026. Until then the mitigations are configuration-level: exclude analytics-bearing routes from the shared cache, or disable the module.

One caveat on step 4: reproducing it proves exposure, but failing to reproduce it does not prove absence. Cache contents turn over, and the window you are testing is not the window that mattered.

The Article 33 Scoping Problem

Article 33(1) GDPR gives you 72 hours from awareness to notify, "unless the personal data breach is unlikely to result in a risk to the rights and freedoms of natural persons." The EDPB sets the awareness threshold at paragraph 31: a controller is "aware" once it has "a reasonable degree of certainty that a security incident has occurred that has led to personal data being compromised."

Then comes the part this incident class makes genuinely hard. Article 33(3)(a) asks you to describe the breach "including where possible, the categories and approximate number of data subjects concerned and the categories and approximate number of personal data records concerned."

Read that qualifier again — where possible. Here it is load-bearing. The identifiers you would normally use to reconstruct who was affected are the identifiers the cache overwrote. Your analytics data does not tell you how many people were exposed; it tells you the same IP address repeatedly, which is the bug rather than the evidence. You can end up certain that disclosure occurred and unable to say to whom.

Two provisions carry you through that, and both are frequently forgotten:

  • Article 33(4) permits phased notification: "Where, and in so far as, it is not possible to provide the information at the same time, the information may be provided in phases without undue further delay." An incomplete picture is not a reason to delay the first notification.
  • Article 33(5) requires you to "document any personal data breaches, comprising the facts relating to the personal data breach, its effects and the remedial action taken", with documentation that "shall enable the supervisory authority to verify compliance." Note any — the documentation duty applies to breaches you correctly decide not to notify, and it is the one obligation here that is unconditional.

Our recommendation, and it is a strong one: document the assessment even where you conclude no notification is required. The cost is an hour. The alternative is a file that shows a supervisory authority nothing but a gap where your reasoning should be. The same logic applies when a vendor advisory lands without evidence of exploitation — a question we work through in our guide on telling a plugin vulnerability from a data breach, which runs the same Article 4(12) apparatus from the opposite direction.

Common Mistakes eCommerce Teams Make

1. Treating "no attacker" as "no breach." This is the worst of the five, because it terminates the analysis before it starts. Article 4(12) and EDPB paragraph 17 both put "accidental" alongside "unauthorised". A team that only recognises intrusions will misclassify this every time.

2. Leaving the CDN off the record of processing activities. If your Article 30 record lists Shopify, Klaviyo and a 3PL but not the cache layer sitting in front of all of them, your record does not describe your processing. A cache stores personal data. That is what caches do. Our guide to building a record of processing activities covers how to capture infrastructure that has no dashboard of its own.

3. Waiting for a CVE before treating something as a privacy issue. There is no CVE for this fix in the public vulnerability databases as of 28 August 2026, and WooCommerce issued no separate security advisory — it appears as one changelog line among many. Severity scoring is a security artefact, not a data-protection one, and Article 4(12) has never mentioned CVSS.

4. Assuming the fix is retrospective. Upgrading to 11.1 stops future disclosure. It says nothing about the period before — which is the period a regulator would ask about.

5. Confusing this with cache poisoning. Hunting for a malicious actor in a case that has none costs you the first day of a 72-hour clock. If your incident plan's opening question is "who did this", it will stall here.

How PrivacyForge Helps

Three parts of this map onto things PrivacyForge already tracks, and one does not.

Your data map is where the cache layer should appear as a system that processes personal data — most Article 30 records catalogue applications and miss the infrastructure underneath them, which is how a CDN ends up undocumented for years. Breach documentation under Article 33(5) wants a durable record of the facts, the effects and the remedial action, including for incidents you assess as non-notifiable; that beats an email thread when a supervisory authority asks a year later. Compliance scoring surfaces a gap like "no documented assessment of technical measures under Article 32(1)(d)" before someone else finds it.

What no compliance platform can do is read your cache key. That is an engineering task, and it belongs to whoever owns your hosting.

Frequently Asked Questions

Is a caching misconfiguration a personal data breach under GDPR?

It can be. Article 4(12) GDPR covers a breach of security leading to the "accidental or unlawful … unauthorised disclosure of, or access to, personal data", so no attacker is required. EDPB Guidelines 9/2022, paragraph 17, classifies a "Confidentiality breach" as an "unauthorised or accidental disclosure of, or access to, personal data" — a cache serving one visitor's identifiers to another fits that definition directly.

Does GDPR treat an IP address as personal data even without a name attached?

Yes. Article 4(1) GDPR includes "an online identifier" in the definition of personal data, and Recital 30 names "internet protocol addresses, cookie identifiers" specifically. It adds that the traces they leave, particularly when combined with other information received by the servers, "may be used to create profiles of the natural persons and identify them" — identifiability, not a name, is the test the Regulation applies.

Do I have to report a breach caused by my own CDN rather than a hacker?

The same Article 33 test applies regardless of cause: notify within 72 hours of awareness unless the breach is "unlikely to result in a risk to the rights and freedoms of natural persons." Cause affects your risk assessment, not whether the duty exists. Article 33(5) separately requires you to document any personal data breach, including one you decide not to notify.

How do I know whether my WooCommerce store was affected?

Check three things in order. First, whether WooCommerce Analytics is running at all — its README requires WooCommerce 3.0+ and, in Phase 1, a Jetpack connection. Second, whether any shared cache sits in front of your storefront. Third, whether that cache varies on cookies and headers for those routes. All three must be true for this mechanism to expose anything.

What is the difference between web cache poisoning and a mis-keyed cache?

Cache poisoning needs an attacker who crafts a request to plant a malicious response. A mis-keyed cache needs nobody: ordinary traffic through a cache whose key omits per-visitor data produces cross-visitor disclosure by itself. The legal outcome can be the same confidentiality breach, but nothing in your logs will look unusual, so detection has to be deliberate.

Conclusion

The uncomfortable part of this story is not the bug. It is that a fix for cross-visitor disclosure of IP addresses and session identifiers shipped as one line in a routine changelog, and nothing in a standard security review would have surfaced it — because nothing anomalous ever happened.

If you run WooCommerce Analytics behind a shared cache, do three things this week: confirm whether you are in scope, plan the 11.1 upgrade landing 1 September 2026, and write down the assessment either way. If you run any other stack, the transferable question is shorter — does anything per-visitor end up inside a response your cache is allowed to share? Ask your hosting provider today rather than your regulator later.

Start with the layer nobody documented: map where personal data actually flows, including the infrastructure between your store and your shopper — the groundwork the rest of GDPR compliance rests on.

Sources