Table of contents of the article:
Introduction
Pixel Your Site (PYS) is one of the most popular WordPress plugins for managing tracking pixels and integrating with major advertising and analytics platforms. It's used to easily configure and manage tools like Facebook Pixel, Google Analytics, TikTok Pixel, Google Ads, and other marketing platforms, without requiring manual changes to your site's code. Thanks to its easy configuration and ability to centralize multiple tracking systems, the plugin has achieved significant popularity across the WordPress ecosystem, with over 500.000 active installations and a widespread presence, especially on eCommerce sites and digital marketing-oriented projects.
This very widespread use makes any security issues in the plugin's code particularly relevant. During an in-depth technical analysis of its internal workings, a vulnerability was discovered that allows an attacker to inject arbitrary domains or text strings into the site's generated HTML. The most critical aspect is that this behavior can be exploited by anyone, without authentication or privileged access to the target site. In other words, you don't need to be an administrator, a registered user, or have any kind of access to the WordPress platform to exploit this issue.
The situation becomes even more problematic when the site uses a caching system, an extremely common configuration in production WordPress sites. Caching plugins like WP Super Cache, W3 Total Cache, WP Rocket, or LiteSpeed Cache—or CDN-level caching systems like Cloudflare—cache HTML pages generated by the server to reduce load and improve performance. If the vulnerability exists, this mechanism can transform attacker-controlled input, normally limited to a single HTTP request, into persistent content that will be served to all subsequent visitors until the cache expires. Effectively, a single malicious request can "poison" the cached version of a page, making the injection visible to thousands of users and even search engine crawlers.
As Michele Genito, a well-known Italian WordPress expert who brought the issue to light and disclosed its technical details, pointed out, the vulnerability has far more serious implications than it might seem at first glance. Although the report was forwarded to the appropriate security channels, the Wordfence team rejected the report, classifying it as not relevant from a security perspective. According to this assessment, the observed behavior would be due to the fact that the Referer field is inherently controllable by the client and therefore does not in itself represent a vulnerability.
Our technical analysis demonstrates why this interpretation is, in our opinion, incomplete and superficial. The problem lies not simply in the possibility of manipulating the referrer—a fact that has always been known in the HTTP context—but in the combination of several architectural factors: the direct use of untrusted inputs, their exposure in the HTML markup served to all users via inline JavaScript, and, above all, the multiplier effect introduced by caching systems. It is precisely this combination that transforms temporary per-request data into persistent content that is potentially exploitable in cache poisoning and SEO manipulation scenarios.
The Mechanism: How PYS Exposes the TrafficSource in the DOM
The plugin generates a global JavaScript variable pysOptions means wp_localize_script(), which is rendered inline in the HTML source of each page:
<script id="pys-js-extra">
var pysOptions = {
...
"tracking_analytics": {
"TrafficSource": "google.com",
"TrafficLanding": "https://esempio.it/pagina/",
"TrafficUtms": { ... },
"TrafficUtmsId": { ... }
},
...
};
</script>
Field Traffic Source Contains the visitor's referring domain. This value is determined server-side by the function getTrafficSource() defined in includes/functions-common.php and inserted into the options array in includes/class-events-manager.php on line 188:
$options['tracking_analytics'] = array(
"TrafficSource" => getTrafficSource(),
"TrafficLanding" => sanitize_url($_COOKIE['pys_landing_page'] ?? $_SESSION['LandingPage'] ?? 'undefined'),
"TrafficUtms" => getUtms(),
"TrafficUtmsId" => getUtmsId(),
);
The array is then serialized into the DOM:
wp_localize_script('pys', 'pysOptions', $data);
Vulnerable Function Analysis
Here is the function getTrafficSource() in its entirety:
function getTrafficSource () {
$referrer = "";
$source = "";
try {
if (isset($_SERVER['HTTP_REFERER'])) {
$referrer = $_SERVER['HTTP_REFERER']; // [1] Input non sanitizzato
}
$direct = empty($referrer);
$internal = $direct ? false : (substr($referrer, 0, strlen(site_url())) === site_url());
$external = !$direct && !$internal;
$cookie = sanitize_text_field(
!isset($_COOKIE['pysTrafficSource']) ? null : $_COOKIE['pysTrafficSource']
); // [2] Cookie controllabile dall'utente
$session = sanitize_text_field(
!isset($_SESSION['TrafficSource']) ? null : $_SESSION['TrafficSource']
);
if (!$external) {
$source = $cookie || $session ? $cookie ?? $session : 'direct';
} else {
$source = ($cookie && $cookie === $referrer)
|| ($session && $session === $referrer)
? $cookie ?? $session
: $referrer; // [3] Referrer usato direttamente
}
if ($source !== 'direct') {
$parse = parse_url($source);
if (isset($parse['host'])) {
return $parse['host']; // [4] Protezione parziale
} elseif ($source == $cookie || $source == $session) {
return $source; // [5] BYPASS: valore restituito senza parse_url
} else {
return defined('REST_REQUEST') && REST_REQUEST ? 'REST API' : "direct";
}
} else {
return defined('REST_REQUEST') && REST_REQUEST ? 'REST API' : $source;
}
} catch (\Exception $e) {
return "direct";
}
}
The critical points
- [1] $_SERVER['HTTP_REFERER'] not sanitized. The HTTP Referer header is entirely client-controllable. Any value can be sent with a simple curl request.
- [2] Controllable pysTrafficSource cookie. The cookie is set client-side by the plugin's own JavaScript, so an attacker can set it to any value.
sanitize_text_field()removes HTML tags but does not prevent the insertion of arbitrary domains or non-HTML text. - [3] Referrer used as source. When the referrer is external and does not match the values in cookie/session, it is used directly as
$source. - [4] parse_url() as partial protection. The code attempts to extract only the host from the value, but this protection is easily circumvented.
- [5] The critical bypass. When
$sourcecorresponds to the cookie or session, the value is returned in full without passing throughparse_url(). This means that an arbitrary value stored in the cookiepysTrafficSourcecan end up directly in the HTML.
The Attack: Cache Poisoning + SEO Poisoning
Cache Poisoning + SEO Poisoning This is an attack technique that exploits website caching systems to insert malicious or manipulated content into cached pages. An attacker sends a specially crafted request that alters the HTML output generated by the server; if the page is cached at that time, the manipulated version will be served to all subsequent visitors. When the injected content includes unwanted domains or external references, the attack can become a SEO poisoning, influencing how search engines interpret the page and associating the victim site with spam domains, malware, or unwanted content.
Prerequisites
- The target site uses Pixel Your Site (any current version)
- The site has an active caching system (WP Super Cache, W3 Total Cache, WP Rocket, LiteSpeed Cache, Cloudflare Page Cache, Varnish Cache, etc.)
- The target page is not yet cached (or the cache has just expired)
Basic attack scenario
# L'attaccante visita la pagina nel momento in cui la cache viene rigenerata
curl -s -H "Referer: https://sito-pornografico.xxx" \
https://sitovittima.it/pagina-importante/ > /dev/null
From now on, the HTML response is cached with the Traffic Source set to the attacker's domain. All subsequent visitors—including search engine crawlers—will see:
var pysOptions = {
"tracking_analytics": {
"TrafficSource": "sito-pornografico.xxx",
...
}
};
Advanced Scenario: Cookie Injection
# L'attaccante imposta il cookie con testo arbitrario
curl -s -b "pysTrafficSource=testo-offensivo-qualsiasi" \
-H "Referer: testo-offensivo-qualsiasi" \
https://sitovittima.it/ > /dev/null
Since the referrer matches the cookie, the code goes into branch [5] and returns the value without domain format validation. sanitize_text_field() It removes HTML tags, but any non-HTML text strings pass through undisturbed.
Concrete impacts
- Negative SEO. A competitor or attacker can associate blacklisted domains (pornography, malware, gambling) with the victim site. Search engine crawlers analyze the full content of the page, including inline JavaScript.
- Competitor sabotage. Entering a direct competitor's domain creates false associations, which search engines could potentially interpret as relationships between the two sites.
- Soft defacement. Even though it is not an XSS (because
wp_localize_script(escapes values), the content is visible in the HTML source. - Persistence. The attack persists for the entire cache lifetime. With common configurations (12–24 hour cache), a single malicious request can poison the page for an entire day.
Why it's not "just a referrer"
The typical response to this class of problems is: "The referrer is always controllable, it's not a vulnerability." This statement is correct in isolation, but it ignores the context.
- The referrer is persisted in the HTML output.
- The cache amplifies the impact.
- No authentication required.
- The attack cost is zero.
Proposed fix
if ($source !== 'direct') {
$parse = parse_url($source);
if (isset($parse['host'])) {
$host = $parse['host'];
} elseif ($source == $cookie || $source == $session) {
$parse_stored = parse_url($source);
$host = isset($parse_stored['host']) ? $parse_stored['host'] : $source;
} else {
return defined('REST_REQUEST') && REST_REQUEST ? 'REST API' : "direct";
}
$host = preg_replace('/[^a-zA-Z0-9.\-]/', '', $host);
if (empty($host) || !preg_match(
'/^([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/',
$host
)) {
return "direct";
}
return $host;
}
What changes
- Elimination of bypass. Values from cookies and sessions are also processed via
parse_url(). - Sanitizing characters. Un
preg_replaceremoves any invalid characters for a domain name. - Format validation. A regex checks whether the result is a syntactically valid domain.
Conclusions
The vulnerability lies in the combination of three factors: untrusted input (Referer and cookie) persisted in HTML output via wp_localize_script(), lack of format validation and caching amplification which makes the injection persistent.
This is not traditional XSS, but classifying a vulnerability solely based on the classic OWASP taxonomy means ignoring real attack vectors. Cache poisoning combined with SEO poisoning is a real, documented, and in this case trivially exploitable risk.
A plugin installed on hundreds of thousands of sites should treat any data coming from the client as potentially malicious — especially when that data ends up in the markup served to all visitors.