Feb 19, 2026·6 min read·64 visits
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.
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 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.
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.
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.
admin@company.com).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"}123-ABC) and constructs the link using the malicious origin: https://attacker-logger.com/user/resetPassword?token=123-ABC.no-reply@appsmith.target-corp.com. Since they might use Appsmith daily, they click the link to reset their password.attacker-logger.com. The attacker's server logs the request path, capturing the token parameter.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:
This is not just a user losing their account; it is a potential full-compromise of the organization's data layer.
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.comIf 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.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Appsmith Appsmith | <= 1.92 | 1.93 |
| Attribute | Detail |
|---|---|
| CVE ID | CVE-2026-22794 |
| CVSS Score | 9.6 (Critical) |
| CWE | CWE-346 (Origin Validation Error) |
| Attack Vector | Network (AV:N) |
| EPSS Score | 0.00012 |
| Exploit Status | PoC Available / Active Exploitation |
The application does not properly verify that the source of data or communication is valid.
CVE-2026-47296 is a high-severity local Elevation of Privilege (EoP) vulnerability in Microsoft SQL Server. The issue stems from the improper neutralization of special elements within internal database routines, allowing a low-privileged authenticated user to execute arbitrary database queries with the privileges of the database owner or system administrator. Microsoft has addressed this vulnerability in its July 2026 security updates.
CVE-2026-47295 is a high-severity elevation of privilege vulnerability in Microsoft SQL Server (2016 through 2025). An authenticated, low-privileged attacker can execute remote SQL injection commands within system stored procedures to elevate permissions to sysadmin.
A stored Cross-Site Scripting (XSS) vulnerability exists within plone.restapi, the REST API package for Plone content management system. By supplying a spoofed input MIME type (text/x-html-safe), an attacker can mislead the rendering layer (plone.app.textfield) into assuming that the supplied content is already sanitized. This causes the system to skip the safe_html transform, allowing arbitrary JavaScript to execute in the victim's browser when they view the compromised page.
An untrusted search path vulnerability in the GlobalDatabasePlugin component of the AWS Advanced JDBC Wrapper for Amazon Aurora PostgreSQL allows authenticated, low-privilege database users to hijack administrative session queries. By defining a custom function in a writable schema such as the public schema, an attacker can hijack queries executed automatically during driver-level topology detection. When a highly privileged database user connects to the database utilizing an affected version of the wrapper, the custom function executes under their security context, enabling remote privilege escalation to rds_superuser.
CVE-2026-27771 represents a critical security flaw in Gitea and Forgejo (up to and including version 1.26.1) involving missing authorization checks (CWE-862). Unauthenticated remote attackers can query, enumerate, and download private container images from the OCI-compliant container registry. Additionally, unauthorized users can retrieve private or internal source repository URLs via the Composer package registry metadata API. A public proof-of-concept exists, and threat metrics indicate highly active scanning and exploitation risks.
A missing authorization vulnerability in the Formie plugin for Craft CMS prior to version 3.1.28 allows low-privileged Control Panel users to read and modify sensitive administrative settings, configuration options, and third-party integrations.