If you run PixelYourSite or PixelYourSite Pro, update it and then purge your page cache. CVE-2026-109987 lets anyone, with no login, plant JavaScript in a cached copy of your page, which your cache then serves to every visitor who comes after. The free plugin alone is on more than 400,000 sites. No attacks have been reported yet, but the proof of concept goes public on November 20, 2026.
At a glance
| CVE | CVE-2026-109987 |
|---|---|
| Plugin | PixelYourSite (400,000+ active installs) and PixelYourSite Pro, the Meta Pixel, Google tag and GTM tracking plugin |
| Type | Unauthenticated stored cross-site scripting (CWE-79), through a cookie value written into the page |
| Severity | CVSS 7.2, high (WPScan and CISA). Some aggregators list it as lower or “unknown”, and NVD hasn’t finished its own analysis |
| Affected | Free before 11.4.3, Pro before 12.6.8, and only on sites that use a full-page cache |
| Fixed | Free 11.4.3 (October 17, 2026). Latest free is 11.4.4 (October 21). Pro 12.6.8 |
| Status | No known exploitation. CISA rates it “automatable”. The proof of concept is due November 20, 2026 |
What’s wrong
The plugin reads a value from a cookie and writes it into the page HTML without sanitizing or escaping it. The vendor’s changelog ties the fix to the plugin’s noscript pixels, the fallback <img> tracking tags inside <noscript> that fire when JavaScript is off. Neither the advisory nor the changelog names the cookie.
A cookie is user input. Whoever makes the request decides what it says. On its own, a bug like this would mostly be self-inflicted: you send a poisoned cookie, you get a poisoned page, and nobody else sees it. A full-page cache changes that. The cache saves the HTML from one visitor’s request and serves it to everyone else, so whatever the first request put into the page becomes part of the page.
That turns into a three-step attack:
- Find a page that isn’t cached yet. A fresh URL, a page whose cache entry just expired, or the whole site right after a cache purge.
- Request it with a crafted cookie. The cookie carries a script payload. PixelYourSite writes it into the HTML, and the cache stores that HTML. Most caches don’t vary their stored copy by cookies they don’t recognize, so nothing stops the save.
- Wait. Every visitor who gets that cached page now runs the attacker’s JavaScript in their browser, on your domain, until the cache entry expires or is purged.
The visitors include you. If a logged-in administrator loads a poisoned page that a cache served to them, the script runs with their session. That opens the door to creating users, changing settings or installing plugins, all as the admin.
What we know about attacks
Nothing so far. WPScan published the advisory on October 20, 2026, and the CVE reached NVD on October 22. Neither reports exploitation, and CISA’s assessment lists exploitation as “none”.
Two details mean that won’t last:
- It’s automatable. CISA says so, and the attack needs no account, no user interaction and nothing site-specific. A scanner can try it against every site that loads PixelYourSite’s pixels, and those are easy to spot from the page source.
- The clock is public. WPScan is holding the proof of concept until November 20, 2026, to give sites time to update. After that, anyone can copy it.
What to do
1. Update
Free: 11.4.3 or later, 11.4.4 as of this writing. Pro: 12.6.8 or later. Pro updates come from the vendor, not WordPress.org, so check that the update actually arrived. The 11.4.3 changelog also fixes a bug where add-on updates weren’t detected by WP-Cron, WP-CLI or the REST API.
2. Purge your page cache
This is the step people will skip. Updating the plugin fixes how new pages are built. It doesn’t touch pages your cache already saved. If someone poisoned a page before you updated, the cache keeps serving it until that entry expires.
Purge everything: the caching plugin (WP Rocket, LiteSpeed Cache, W3 Total Cache, WP Super Cache and the like), your host’s server cache, and any CDN in front of the site. Do it after the update, not before.
3. Check whether you were hit
If the site ran a vulnerable version behind a cache, look before you purge, or save a copy of the cache directory first:
- Cached HTML. Search the cache for
<script,javascript:,onerror=oronload=inside the plugin’s<noscript>blocks. Legitimate noscript pixels are plain<img>tags pointing at tracking URLs. - Access logs for unusually long or encoded
Cookieheaders on page requests, if your logs record them. Most default logs don’t. - Users. Look for administrator accounts you didn’t create.
- Plugins and must-use plugins. Look for anything you didn’t install, including in
wp-content/mu-plugins/.
If an administrator may have loaded a poisoned page, treat the admin session as compromised: log out all sessions, change the passwords and replace the salts in wp-config.php.
4. Watch for injected scripts with a Content Security Policy
A Content Security Policy tells browsers which scripts a page may run. Tracking plugins load scripts from many places, so a strict policy can break things. Start in report-only mode: it blocks nothing, but browsers report any script that wouldn’t pass. On Apache or LiteSpeed, in .htaccess:
<IfModule mod_headers.c>
Header set Content-Security-Policy-Report-Only "script-src 'self' https://connect.facebook.net https://www.googletagmanager.com https://www.google-analytics.com; report-uri /csp-report"
</IfModule>
Adjust the list to the services you actually use, and point report-uri at somewhere that collects reports. An inline script injected by an attacker shows up as a violation. Once the reports are quiet, you can switch to an enforcing policy.
The bigger lesson
Cookies, headers and query strings are user input, just as much as a form field. Plugin code that reads one and prints it straight into the page is a bug even when it looks harmless, and the usual excuse, “an attacker can only target themself”, stops being true the moment a cache sits in front of the site. Caching turns reflected bugs into stored ones. Any plugin that writes request data into a cacheable page has to escape it, every time.
It’s also a reminder of why every plugin should earn its place. A tracking plugin runs on every page, for every visitor, and its output gets cached along with your content. That’s a large footprint for code whose job is marketing. If you need the pixels, keep the plugin updated. If you don’t, removing it closes this hole and the next one.