CVEReports
Reports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Reports
  • Sitemap
  • RSS Feed

Company

  • About
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Powered by Google Gemini & CVE Feed

|
•

CVE-2026-21446
CVSS 9.8

Bagisto's Open House: How an AJAX Header Stole the Admin Panel

Alon Barad
Alon Barad
Software Engineer•January 2, 2026•5 min read
PoC Available

Executive Summary (TL;DR)

Bagisto left the installer routes active after installation but tried to hide them with a redirect. The catch? The redirect only applied to standard browser requests. By adding a simple `X-Requested-With: XMLHttpRequest` header, attackers can bypass the check, access the installer API, and overwrite the primary administrator account.

A logic flaw in Bagisto's installer middleware allows unauthenticated attackers to re-run the installation process via AJAX requests, enabling complete administrative takeover.

The Hook: Zombie Installers

Installers are the most dangerous code in any web application. They are designed to create databases, write configuration files, and mint the first omnipotent administrator account. Because of this power, the golden rule of secure development is: The installer must die after it runs. Most CMS platforms delete the install folder or place a lock file (like install.lock) on the disk.

Bagisto, a Laravel-based e-commerce platform, took a different approach. Instead of deleting the code, they relied on middleware to act as a bouncer. The middleware, aptly named CanInstall, was supposed to check if the shop was already set up and kick you out if you tried to sneak back into the setup wizard.

But here's the problem with software bouncers: they strictly follow rules, and if the rules have a loophole, the bouncer will hold the door open for you while you rob the place. CVE-2026-21446 is that loophole—a trivial logic error that turns a locked-down store into a free-for-all.

The Flaw: The AJAX Blindspot

The vulnerability resides in packages/Webkul/Installer/src/Http/Middleware/CanInstall.php. This code runs before any request hits the installer routes. Its job is simple: If the app is installed, redirect the user to the homepage.

However, the developers added a condition that proved fatal. They likely wanted to prevent the redirect from messing up frontend JavaScript calls during the legitimate installation process. So, they explicitly checked if the request was not AJAX before redirecting.

[!WARNING] The Logical Fallacy The code effectively said: "If the app is installed AND the user is browsing normally, stop them. Otherwise, let them through."

If you send a request that claims to be AJAX (by setting the standard X-Requested-With: XMLHttpRequest header), the middleware looks at the logic ! $request->ajax(), evaluates it to false, and skips the redirect block entirely. The request then proceeds straight to the controller, regardless of whether the application is already installed.

The Code: The Smoking Gun

Let's look at the diff. This is a classic case of "negative security logic"—defining what should be blocked instead of what should be allowed.

Vulnerable Code (Simplified):

public function handle(Request $request, Closure $next)
{
    // If we are hitting installer routes...
    if (Str::contains($request->getPathInfo(), '/install')) {
        // ...and we are already installed...
        // ...BUT it is NOT an AJAX request...
        if ($this->isAlreadyInstalled() && ! $request->ajax()) {
            // ...then redirect.
            return redirect()->route('shop.home.index');
        }
    }
    // Otherwise, come on in!
    return $next($request);
}

The Fix (Commit 380c045e48490da740cd505fb192cc45e1809bed): In the patch, the logic is inverted. If the app is installed, it denies access immediately. It handles the user experience gracefully (JSON for AJAX, Redirect for Browser), but the deny decision is absolute.

if ($this->isAlreadyInstalled()) {
    // If it's AJAX, give them a 403 Forbidden
    if ($request->ajax()) {
        return response()->json([
            'message' => 'Already Installed'
        ], 403);
    }
    // If it's a browser, redirect them
    return redirect()->route('shop.home.index');
}

Furthermore, the InstallerController was using updateOrInsert with a hardcoded id => 1. This meant valid requests would overwrite the existing admin rather than failing. The patch changed this to a strict insert, ensuring that even if the middleware failed, the database constraints would block a duplicate admin creation.

The Exploit: Overwriting God Mode

Exploiting this is trivially easy. We don't need fancy memory corruption tools; we just need curl.

The target is the /install/api/admin-config-setup endpoint. In the vulnerable version, this endpoint accepts admin credentials and commits them to the database using updateOrInsert(['id' => 1], ...).

The Attack Chain:

  1. Target: Identify a Bagisto store (v2.3.x).
  2. Payload: Construct a POST request with new admin credentials.
  3. Bypass: Add the magic header X-Requested-With: XMLHttpRequest.

PoC:

curl -X POST https://vulnerable-store.com/install/api/admin-config-setup \
  -H "X-Requested-With: XMLHttpRequest" \
  -H "Content-Type: application/json" \
  -d '{
    "admin": "hacked_admin",
    "email": "attacker@evil.com",
    "password": "Pwned123!",
    "password_confirmation": "Pwned123!"
  }'

Because the middleware sees the header, it allows the request. Because the controller forces id => 1, the database updates the existing primary administrator's row with the attacker's email and password. The attacker can now log in to the backend, upload a malicious theme or plugin, and achieve Remote Code Execution (RCE).

The Impact: Why This Matters

This is a Critical (9.8) severity issue because it breaks the fundamental trust model of the application. Authentication is bypassed not by cracking a password, but by asking the application nicely to reset it.

Once an attacker has administrative access to an e-commerce platform like Bagisto, the impact is total:

  • Data Theft: Exporting all customer data (PII, addresses, order history).
  • Financial Fraud: Modifying payment gateways to divert funds or creating fake orders.
  • Server Compromise: Laravel admins usually have the ability to modify templates or upload files. This leads to shell access, allowing the attacker to pivot into the internal network.

It is effectively a "Game Over" scenario accessible to anyone who can send a single HTTP request.

The Fix: Closing the Door

The remediation is straightforward: Update to Bagisto 2.3.10 immediately.

If you cannot update right now, you must block the installer routes at the web server level. The application code failed to protect these routes, so the infrastructure must step in.

Nginx Mitigation:

location ~ ^/install {
    deny all;
    return 404;
}

This rule ensures that no matter what headers are sent, the web server drops the connection before it ever reaches PHP. This is a good practice for any application with an installer directory—don't rely on the app to protect itself from its own setup wizard.

Official Patches

BagistoOfficial patch commit

Fix Analysis (1)

Technical Appendix

CVSS Score
9.8/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Affected Systems

Bagisto eCommerce Platform

Affected Versions Detail

ProductAffected VersionsFixed Version
Bagisto
Webkul
>= 2.3.0, < 2.3.102.3.10
AttributeDetail
CWE IDCWE-306
CVSS Score9.8 (Critical)
Attack VectorNetwork (Remote)
AuthenticationNone
ImpactAccount Takeover / RCE
Exploit StatusPoC Available

MITRE ATT&CK Mapping

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1078Valid Accounts
Defense Evasion
CWE-306
Missing Authentication for Critical Function

The software does not perform any authentication for functionality that requires a provable user identity or consumes a significant amount of resources.

Exploit Resources

Known Exploits & Detection

N/AExploit methodology described in GHSA advisory

Vulnerability Timeline

Vulnerability Timeline

CVE Published
2026-01-02
Patch Released (v2.3.10)
2026-01-02

References & Sources

  • [1]GitHub Security Advisory
  • [2]NVD Record

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.