CVEReports
CVEReports

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

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-22794
9.60.01%

Trust Issues: How a Single Header Toppled Appsmith

Alon Barad
Alon Barad
Software Engineer

Feb 19, 2026·6 min read·27 visits

Active Exploitation

Executive Summary (TL;DR)

Appsmith <= 1.92 allowed attackers to hijack user accounts by manipulating the HTTP 'Origin' header during password reset requests. This caused the server to generate and email reset links pointing to an attacker-controlled domain. Clicking the link leaked the reset token to the attacker, granting full account access. Fixed in version 1.93.

In the world of web security, there is a golden rule that is broken so often it should be printed on the back of every developer's eyelid: **Never trust client input.** Yet, here we are again with CVE-2026-22794, a critical Account Takeover (ATO) vulnerability in Appsmith, the darling of the open-source low-code world. The vulnerability is a classic case of 'Origin Validation Error' (CWE-346). By blindly trusting the HTTP `Origin` header to construct sensitive password reset links, the Appsmith server allowed attackers to redirect the password reset flow to their own domains. This isn't just a minor glitch; it's a mechanism that turns the application's own email service into a weapon, handing over administrative keys to anyone with `curl` and a lack of morals. The fix involves finally forcing the server to know its own name via a hardcoded configuration rather than asking the stranger knocking at the door.

The Hook: The Low-Code Trojan Horse

Appsmith is a fantastic tool. It allows developers to whip up internal dashboards, admin panels, and CRUD apps in minutes. It connects to everything—PostgreSQL, MongoDB, AWS S3, you name it. And that is exactly why this vulnerability is terrifying.

Usually, when we talk about Account Takeover (ATO), we're worried about someone reading your emails or posting embarrassing tweets. But with Appsmith, an ATO doesn't just give you access to a user profile; it gives you the keys to the kingdom's backend. You aren't just compromising a user; you are compromising the database credentials and API keys stored within that user's projects.

Prior to version 1.93, Appsmith suffered from a severe identity crisis. It didn't inherently know where it lived. Instead of having a strict, server-side concept of "Home," it relied on the incoming HTTP request to tell it where to send users. It's the digital equivalent of a bank asking a robber, "Which vault would you like me to open for you?" and then politely holding the door.

The Flaw: The Sin of Origin

The root cause here is a failure to sanitize the Origin header (or sometimes the Host header, depending on the specific proxy setup). In a modern web stack, the Origin header is sent by the browser to indicate where a request is coming from. It is client-controlled data. It is untrusted. It is dirty.

When a user requests a password reset, the server needs to generate a link like https://appsmith.company.com/reset?token=XYZ. To build this string, the code needs three things: the protocol (https), the domain (appsmith.company.com), and the token (XYZ).

The developers of Appsmith made a fatal assumption: they assumed that the Origin header in the request matched the actual domain of the application. They wrote code that essentially said: "Take whatever the user claims is the base URL, append the token, and email it to the victim."

This is a logic flaw known as CWE-346: Origin Validation Error. By failing to validate this input against a whitelist or a static configuration variable, the application became a proxy for phishing attacks, signed and delivered by its own SMTP server.

The Code: Anatomy of a Screw-Up

Let's look at the "smoking gun" in UserServiceCEImpl.java. This is where the magic (and the tragedy) happened.

The Vulnerable Code (Conceptual):

Before the patch, the code logic looked something like this:

// Inside forgotPasswordTokenGenerate
public Mono<Boolean> forgotPasswordTokenGenerate(ResetUserPasswordDTO resetUserP) {
    // DANGER: relying on the DTO which was populated from the HTTP headers
    String baseUrl = resetUserP.getBaseUrl(); 
    String token = UUID.randomUUID().toString();
    
    // Constructing the link using the attacker-supplied base URL
    String resetLink = String.format("%s/user/resetPassword?token=%s", baseUrl, token);
    
    // The server happily sends this link to the victim
    return emailService.sendForgotPasswordEmail(email, resetLink);
}

The Fix (Commit 6f9ee622...):

The remediation was to stop trusting the request and start trusting the configuration. They introduced a check against APPSMITH_BASE_URL.

@Value("${APPSMITH_BASE_URL:}")
private String appsmithBaseUrl;
 
private Mono<Void> validateBaseUrl(String providedBaseUrl) {
    // If the admin hasn't set the config, we are still vulnerable (backward compat)
    if (!StringUtils.hasText(appsmithBaseUrl)) {
        return Mono.empty(); 
    }
    // The validation logic
    if (!appsmithBaseUrl.equals(providedBaseUrl)) {
        return Mono.error(new AppsmithException(
                AppsmithError.GENERIC_BAD_REQUEST,
                "Origin header does not match APPSMITH_BASE_URL configuration."));
    }
    return Mono.empty();
}

> [!NOTE] > Notice the check !StringUtils.hasText(appsmithBaseUrl). Even with the patch, if the administrator does not explicitly set the APPSMITH_BASE_URL environment variable, the check is skipped to maintain backward compatibility. This means patching alone isn't enough; you must configure the environment correctly.

The Exploit: Phishing with Precision

Exploiting this requires no authentication and can be automated. Here is how an attacker turns a standard password reset feature into an account hijacking machine.

The Attack Chain

  1. Reconnaissance: The attacker identifies the target Appsmith instance and the email address of a victim (e.g., admin@company.com).
  2. The Injection: The attacker sends a POST request to the password reset endpoint, but injects a malicious Origin header.
POST /api/v1/users/forgotPassword HTTP/1.1
Host: appsmith.target-corp.com
Origin: https://attacker-logger.com
Content-Type: application/json
 
{"email": "admin@company.com"}
  1. The Delivery: The Appsmith server generates a token (let's say 123-ABC) and constructs the link using the malicious origin: https://attacker-logger.com/user/resetPassword?token=123-ABC.
  2. The Click: The victim receives a legitimate-looking email from no-reply@appsmith.target-corp.com. Since they might use Appsmith daily, they click the link to reset their password.
  3. The Capture: The victim's browser navigates to attacker-logger.com. The attacker's server logs the request path, capturing the token parameter.
  4. The Takeover: The attacker takes the stolen token and submits it to the real Appsmith instance to set a new password for the admin account.

The Impact: Why You Should Panic

This vulnerability scores a CVSS 9.6 for a reason. In a corporate environment, Appsmith is rarely used for trivial tasks. It is the glue code for internal operations.

If an attacker compromises an Appsmith admin account, they likely gain:

  1. Database Access: Read/Write access to every datasource connected to the Appsmith instance (production SQL databases, customer records).
  2. API Keys: Access to stored secrets and API tokens for third-party services (Stripe, Twilio, AWS).
  3. Internal Network Access: The ability to run queries from the Appsmith server, often bypassing other firewall rules or VPN restrictions because the requests originate from a trusted internal server.

This is not just a user losing their account; it is a potential full-compromise of the organization's data layer.

The Fix: Plugging the Hole

Remediation is a two-step process. Do not skip step 2.

Step 1: Upgrade Update your Appsmith instance to version 1.93 or later immediately. This introduces the code capable of validating the header.

Step 2: Configure You must define the APPSMITH_BASE_URL environment variable in your docker-compose.yml or Kubernetes deployment. This tells Appsmith exactly what its public URL is, so it stops guessing based on attacker input.

services:
  appsmith:
    environment:
      - APPSMITH_BASE_URL=https://appsmith.yourcompany.com

If you fail to set this variable, the patch code we analyzed earlier will simply return Mono.empty() and bypass the validation check, leaving you just as vulnerable as before. Don't be that person.

Official Patches

AppsmithGitHub Advisory GHSA-7hf5-mc28-xmcv

Fix Analysis (1)

Technical Appendix

CVSS Score
9.6/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H
EPSS Probability
0.01%
Top 98% most exploited

Affected Systems

Appsmith Community Edition <= 1.92Appsmith Enterprise Edition <= 1.92

Affected Versions Detail

Product
Affected Versions
Fixed Version
Appsmith
Appsmith
<= 1.921.93
AttributeDetail
CVE IDCVE-2026-22794
CVSS Score9.6 (Critical)
CWECWE-346 (Origin Validation Error)
Attack VectorNetwork (AV:N)
EPSS Score0.00012
Exploit StatusPoC Available / Active Exploitation

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1566Phishing
Initial Access
T1078Valid Accounts
Persistence
CWE-346
Origin Validation Error

The application does not properly verify that the source of data or communication is valid.

Known Exploits & Detection

ResecurityTechnical analysis and PoC for Origin manipulation
NucleiDetection Template Available

Vulnerability Timeline

Fix commit pushed to GitHub
2025-11-28
CVE Published and Advisory Released
2026-01-12
Active Exploitation Reported by Resecurity
2026-01-21
Formal Security Notice Issued
2026-01-23

References & Sources

  • [1]Official Appsmith Security Advisory
  • [2]NVD Entry for CVE-2026-22794

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.