360XSS: Mass Website Exploitation via Virtual Tour Framework for SEO Poisoning
Hackers are exploiting a reflected XSS vulnerability in the "Krpano" VR library across hundreds of websites, injecting malicious scripts to hijack Google’s search index and distribute spam ads at scale.

How I Accidentally Uncover One of the Most Exploited XSS Vulnerabilities Online
My story begins in a way that many readers of technical blogs might find familiar—just another uneventful evening alone at the computer. For purely educational purposes, I opened a Chrome incognito window, went to Google, and typed the word “porn.” Thanks to my ongoing research in this area, I’m quite familiar with the usual search results. But this time, something unusual caught my eye—a new website appearing in the third row, listed under Yale University’s domain with the title: “++[S*X@Porn-xnxx-Videos!…] Tamil sexy student.” It piqued my curiosity, but not for the reasons you might think.

Did Yale University Enter the Porn Industry?
I was almost certain the website had been hacked, but I still wasn’t sure how. My first thought was a subdomain takeover—a common attack where an abandoned CNAME record pointing to an unused asset gets hijacked by an attacker to host malicious content under the original domain. I had previously explored this technique in my research at Guardio, where I coined the term “Subdomailing”.
To test my theory, I clicked the link to see where it would take me. The page initially loaded what looked like a legitimate platform but quickly redirected me to a random porn ad.
https://virtualtour.quantuminstitute.yale.edu/?id=yuxs&xml=https://staging-prep-cms.scouts.org.uk/lnk/video/?video=video-xx-indain-girl-xxx-xxxxxxx-xvid-60159.html
Examining the original URL, a few things stood out: the subdomain name hinted that the site was related to a virtual tour, and an xml
parameter contained a suspicious-looking URL—something that definitely needed a deeper look.
Curious, I tried opening the same URL again but without the parameters—and suddenly, I found myself inside Yale’s Quantum Mechanics Institute. Took a quick tour, impressive place. If you're into quantum computing, worth a look. But honestly, I never really got superposition—how can a bit be both 0 and 1? Seriously, how does that work?? 😂

…Anyway, back to the point.
Reversing the Payload
The xml
parameter was clearly the key factor, so I considered the possibility of an open redirect. I modified the parameter value to https://www.example.com, expecting a redirection—but instead, the page threw an error:

At that point, I knew this was more than just a simple redirect. I hadn’t even checked the original xml
parameter yet—and when I did, one thing stood out: the URL belonged to the official UK Scouts website, which seemed suspicious. A quick DNS check confirmed my suspicion—the subdomain had been hijacked through an abandoned Azure account, just as I had explained earlier.

Then, I examined the response contents of the URL to see what was inside:

The response was an XML document with an onloaded
event containing an eval
function executing a Base64-encoded payload—one of the most classic indicators of a malicious XSS (Cross-Site Scripting) payload.
At that moment, I felt a rush of excitement—this was the first time I had found an actively exploited XSS in the wild. Don’t get me wrong—I strongly oppose malicious activities like this, but the researcher in me couldn’t help but celebrate 😂.

Beyond the XSS, the main tag <krpano>
revealed the underlying technology powering my virtual tour through the quantum institute.
That meant the XSS was either in the framework itself or in the website’s implementation.
Curious to understand what the payload actually did, I decoded it:

Nothing particularly sophisticated stood out in the script—except that it fetched a target URL from yet another stolen asset, this time volvo.com, and used the id
parameter to identify the ad campaign.
At this point, I hadn’t even fully started my investigation, and I had already found three abused assets from three major organizations. That’s when I realized—this wasn’t just some random hacker selling services on Telegram. I was dealing with a serious actor—someone with a massive bank of stolen assets and a well-organized operation.
Zero Day or One Day?
Reversing this XSS was a fun ride. At first, I assumed the external XML loading was an intended feature of the Krpano library and that the vulnerability lay in how the XML was parsed. So, I dived into debugging the obfuscated library, searching for the source of truth. After 30 minutes of digging, I finally did what I should’ve done from the beginning—checked the documentation. And there it was:
The XML onloaded
attribute? A documented feature.
The external xml
parameter? A design choice - one that should be disabled in production.
I came across a crucial configuration setting - passQueryParameter
.

This setting controls whether query parameters from the hosting website are directly passed into Krpano’s configuration. The problem? For years it was enabled by Krpano's default installation. Meaning, any attacker could inject arbitrary XML, leading to reflected XSS if a vulnerable website didn’t explicitly disable it.
Digging deeper, I found CVE-2020-24901. The description matched exactly what I observed: reflected XSS caused by the passQueryParameter
setting. While the original POC used different parameters, the xml
parameter was also mentioned. So, was this a one-day? Yes. But somehow, it slipped past too many websites, as you're about to see.
The Shoemaker's Children Go Barefoot
In this Krpano forum thread, a user raised concerns about this CVE—a full year after its disclosure. Krpano’s developers downplayed the issue, claiming it was a case of misuse rather than a security flaw. However, they did mention that as of version 1.20.10
, they restricted passQueryParameter
to an allowlist in an attempt to prevent XSS.
But here’s the problem.
Explicitly adding the xml
parameter to the allowlist still left the same XSS risk open, and this configuration remained available for use.
And now, for the best part.
While browsing Krpano's documentation, I noticed they hosted live examples of their 360° tour framework on their own website. Naturally, I checked their implementation… and guess what? They were vulnerable too.

A Simple XSS Is Powering a Massive Ad Campaign Operation
Once I cracked the technical side of the vulnerability, I shifted gears—I wanted to understand the bigger picture. How widespread was this campaign? How many other sites had been exploited? That’s when an idea hit me. Instead of chasing leads blindly, why not use my good old friend, Google Dorking?
inurl:xml=https AND inurl:id=
And just like that, I opened the Pandora box.

The sheer scale of this campaign caught me off guard. With a couple of Google searches, I uncovered thousands of ads spread across 350+ exploited websites—and not just any websites.
Government portals. Entire state websites. Top universities in America. Major hotel chains. News outlets. Car dealerships. Fortune 500 companies. All hijacked and repurposed as SEO tools to spread spam, ads, and shady promotions.
Most of these sites were very popular and are having millions of visitors each month, and some had been hit multiple times, serving different types of ads.
And it wasn’t just porn ads anymore. I found diet supplements, online casinos, fake news sites—every kind of sketchy ad we instinctively close without a second thought. But the real surprise? Some of these hijacked pages weren’t even pushing ads—they were being used to boost YouTube views.
This wasn’t just a spam operation. It was an industrial-scale abuse of trusted domains.

I also analyzed the xml parameter value. Some were the usual suspects: cheap, throwaway domains registered with privacy-shielded WHOIS info, making it impossible to trace the owners. But others? Hijacked subdomains of major websites.
XSS for SEO Poisoning
Everything about this campaign screamed SEO pros. One of the biggest proofs was right at the beginning of this blog—where I showed how they pushed their ad to the third row in Google search results for one of the most searched terms in the world: "porn". Sure, leveraging Yale University’s domain played a big role in boosting credibility, but pulling off that level of ranking manipulation is still no small feat.
In addition to that, the concept itself of a reflected XSS that is used to be promoted in SEO results… Is nothing I’ve seen before, not at this scale. A reflected XSS is a fun vulnerability but on it’s own requires user interaction, and one of the biggest challenges is to make people click your reflected XSS link. So using search engines as a distribution platform for your XSS is a very creative and cool way to do it.
These guys squeeze every last drop out of every website they compromise. Take Utah’s official website, for example—at the time of my search, it had over 100 indexed spam results.

And keep in mind, my data was limited to Google Dorks, meaning they had likely indexed the same page with different ads hundreds of times beyond what I could see.
They weren’t just injecting links—they were optimizing them:
- Controlled the title, description, and preview image.
- Used random strings in titles to make each result unique.
- Added fake review counts and star ratings.
I can’t accurately estimate how many clicks this campaign generated, but judging by its scale, millions wouldn’t be a stretch.

But there was still one question that kept bugging me…
Why Only Ad Redirects?
For some reason, I always assumed that the best way to exploit an XSS was to directly attack the vulnerable website and its user base—stealing cookies, session tokens, or performing actions on behalf of users. However, in this case, all I found was JavaScript executing simple redirects and nothing more 🤔.
Thinking logically, I came up with two possible reasons why they chose this approach:
- They're likely a shady ad firm, more interested in blasting ads everywhere than launching direct cyberattacks. This is probably their most effective monetization strategy.
- They’re operating in a legal gray area—while their methods are unethical, they aren't outright criminal. If they stole user data or launched full-fledged attacks, it would escalate the operation into something that attracts law enforcement and investigations. However all they did was to distribute ads.
But then, while digging through the scraped websites, I stumbled upon something bigger—a website with over half a billion monthly visitors that was treated specially.
CNN - More Than a Redirect
This wasn’t just another case of a high-traffic website being compromised. What made it stand out? Clicking the malicious link didn’t redirect me elsewhere—it kept me right on cnn.com, landing on what appeared to be a legitimate CNN article. Same domain, same structure—except the content was in Turkish and the title was “Top Reliable Casinos Online.”
Who wouldn’t trust an article hosted on CNN, especially when hunting for the most “reliable” online casino?

This was a smoking gun—proof the attackers knew exactly what they had in their hands. Instead of a cheap redirect, which would be a waste, they embedded their casino promotion directly inside CNN’s domain, disguising it as a real article. They weren’t just hijacking traffic; they were weaponizing trust.
Digging deeper, the xml payload was hosted on this “unsuspicious” domain "jqeury.store". The homepage on that domain served a list of links to multiple instances of the same CNN exploit, each serving different variations of the casino article.

But it didn’t stop there. Some links also pointed to "geo.tv"–Pakistan’s largest news site. Opening them revealed the same trick—fake articles injected into a vulnerable endpoint, all promoting the same casino.

Responsible Disclosure
The people behind this campaign remain a mystery, but from what I’ve seen, many clues suggest it was run by an Arab group—based on the ads, patterns, and random breadcrumbs I found during my investigation. Either way, I couldn’t care less; that’s a problem for law enforcement. What I can do, however, is try to minimize the damage by reaching out to the biggest brands affected.
I set out to report as many exploited instances as possible. What I didn’t anticipate was just how difficult that would be. I personally uncovered over 300 exploited domains, yet most had no vulnerability disclosure program. Hours went into tracking down contact emails and submission forms, but most of my reports went nowhere—buried in unread inboxes or bounced back with no response.
Still, there were wins. Some reports made it through, earning me acknowledgements from major organizations like U.S. Department of Health & Human Services and CERT-EU. A handful of vulnerable assets even got fixed—some thanks to my disclosures, others by sheer coincidence.
That’s when I decided to start my own blog—to shed light on overlooked attack vectors and reach a wider audience. If there’s one thing this experience reinforced, it’s that these problems extend far beyond a handful of exploited domains—and they don’t get fixed until someone makes enough noise.
Krpano’s Response
Alongside my reporting mission, I reached out to Krpano’s developers to highlight the vulnerable implementation on their own website and raise concerns about the handling of the XML parameter. The library’s main developer, Klaus, responded promptly and professionally, taking my report seriously. Within a few weeks, he implemented a fix in version 1.22.4
, restricting external resources from being loaded through the XML parameter—effectively closing off this attack vector.
Big kudos to Klaus 👑

360XSS: How to Fix It?
🔍 Identify all instances of Krpano on your website.
⬆️ Update to the latest version 1.22.4
.
❌ Set the passQueryParameter
configuration to false
.
🔍 Scan for SEO Poisoning – Find and remove infected pages via Google Search Console.
Stay Safe 💪🏻