CVE-2026-109653
Executive Summary
CVE-2026-109653 is a stored cross-site scripting (XSS) vulnerability in Frappe ERPNext affecting versions before 15.119.0 and 16.x before 16.31.0. A low-privilege authenticated user can persist a malicious payload into a record field that is later rendered into an HTML attribute context without escaping, executing script in the browser of any privileged user who views the affected page. Successful exploitation enables session/account takeover of high-privilege ERPNext users, exposing financial, HR, and operational data governed by the platform.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
The flaw is classified as CWE-79 (Improper Neutralization of Input During Web Page Generation, i.e., cross-site scripting). The NVD description states that record fields are rendered into an HTML attribute context without escaping. This is a classic stored (persistent) XSS condition where the output-encoding step fails to apply context-appropriate escaping for an HTML attribute.
Mechanism (vulnerability-class level):
- ERPNext stores user-supplied field content in its backing database as part of a record (e.g., a saved document/record field).
- When the affected page is rendered, that stored field value is written into an HTML attribute (e.g., a
title=,value=,data-*, or similar attribute position) rather than a text node. - Because the value is not attribute-escaped, an attacker who controls the field content can break out of the attribute context and inject an event handler or otherwise cause the browser to interpret injected markup as executable content.
- This requires a low-privilege authenticated user (
PR:L) to have write access to the record field, and a privileged victim (UI:R) to open the affected page.
Attack surface: any ERPNext view that renders recorded field values into attribute positions. Because the payload is stored, no interaction with the attacker's controlled endpoint is required at victim-render time — the persistence in the record itself carries the payload.
Encoding-context note: HTML attribute contexts require different escaping rules than text/HTML-body contexts (for example, attribute values need quoting plus encoding of quotes, and event-handler attributes additionally require JavaScript-context encoding). The reported absence of attribute-context escaping is the root cause. No specific function, parameter, or endpoint names are provided in the intelligence data, so no code-level symbols should be assumed.
Sparse-data note: The provided data does not identify specific record types, field names, routes, or rendering templates. The analysis above is deliberately limited to the vulnerability class and the mechanism described verbatim by NVD.
Exploitation Scenarios
No public PoC is available; the attack chain below is inferred from the vulnerability class (stored XSS in an attribute context) and the NVD description, and does not assert specific endpoints or parameters.
Reconnaissance / target identification
- The attacker identifies an internet- or intranet-exposed ERPNext instance (Shodan dork
http.title:"ERPNext"orhttp.html:"/assets/erpnext/"). - The attacker obtains a low-privilege authenticated account, either legitimately or via a separately obtained credential, because the CVSS vector requires
PR:L(privileges required: low).
- The attacker identifies an internet- or intranet-exposed ERPNext instance (Shodan dork
Triggering the specific flaw class
- The attacker creates or edits a record and supplies a crafted value in a field that is later rendered into an HTML attribute position.
- The payload is persisted in the ERPNext database (stored XSS) rather than reflected at request time.
Payload / execution method (vulnerability-class level)
- When a privileged user opens the affected page, the stored field value is emitted into the HTML attribute without escaping.
- The browser parses the injected content in the page origin, so any script the attacker embedded executes with the victim's session privileges.
- Because execution occurs in the application origin, same-origin protections (cookies, CSRF tokens in page context, authenticated APIs) are within reach of the script.
Post-exploitation impact
- Session/account takeover of the privileged user (NVD: "enabling account takeover").
- Confidentiality: high (
C:H) — ERPNext records (financial, HR, customer data) readable with the victim's access. - Integrity: high (
I:H) — privileged actions (record modification, workflow approval, user administration depending on victim role) can be performed as the victim. - Availability: none (
A:N) per vector.
Constraints/uncertainty: no public exploit code, no Nuclei template, and no exploit-in-the-wild evidence were provided. The exact field and page involved must be confirmed against a live, authorized test instance.
Impact Assessment
- Severity: CVSS v3.1 base score 7.3 (High). Vector CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N.
- Attack Vector (AV:N): Network-exploitable.
- Attack Complexity (AC:L): No specialized conditions beyond field control and victim interaction.
- Privileges Required (PR:L): A low-privilege authenticated account suffices to store the payload.
- User Interaction (UI:R): A privileged user must open the affected page.
- Scope (S:U): Impact confined to the vulnerable ERPNext security authority.
- C/I/A: High confidentiality and integrity impact; no availability impact.
Business blast radius:
- ERPNext is a widely deployed open-source ERP covering accounting, HR, inventory, manufacturing, CRM, and support. A takeover of a privileged ERP user can expose financially and legally sensitive records and allow fraudulent or destructive record changes.
- The stored nature of the payload makes it reusable against every privileged user who opens the affected page until the record is remediated — a single injection can compromise multiple administrators over time.
- ERPNext is frequently internet-facing for remote workforce access, increasing exposure.
- Because the bug is unpatched per tracked evidence (0/4), organizations cannot rely on vendor updates alone and must apply compensating controls.
- No CISA KEV listing and no known in-the-wild exploitation were reported in the provided data; EPSS is not yet scored by FIRST.org, so no EPSS value is asserted here.
Detection Guidance
Sigma Rule
title: ERPNext Stored XSS - Attribute-Context Payload Submission to Record Fields
id: 8f2c1a44-7c6e-4d1a-9b2e-erpnext-xss-001
status: experimental
description: Detects creation or update of ERPNext records containing HTML/JS delimiters typical of attribute-context stored XSS payloads.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-109653
author: valtersit.com
date: 2026/01/01
logsource:
product: erpnext
category: application
detection:
selection_method:
http.method:
- POST
- PUT
selection_path:
http.url|contains:
- '/api/resource/'
- '/api/method/'
selection_payload:
http.request.body|contains:
- '"><'
- "'><"
- '"><script'
- 'javascript:'
- 'onerror='
- 'onload='
- 'onmouseover='
- 'svg/onload'
- '<script'
condition: selection_method and selection_path and selection_payload
falsepositives:
- Legitimate rich-text content that includes HTML with proper sanitization upstream
- Security scanning or fuzzing against the API
level: high
tags:
- attack.t1059.007
- cve.2026.109653
YARA Rule
rule CVE_2026_109653_ERPNext_Stored_XSS_Attribute_Payload
{
meta:
description = "Detects stored XSS payloads targeting HTML attribute context in Frappe ERPNext records (CVE-2026-109653)"
author = "valtersit.com"
date = "2026-01-01"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-109653"
cve = "CVE-2026-109653"
strings:
$attr_break1 = "\"><" ascii nocase
$attr_break2 = "'><" ascii nocase
$attr_break3 = "\\\" on" ascii nocase
$js1 = "javascript:" ascii nocase
$js2 = "onerror=" ascii nocase
$js3 = "onload=" ascii nocase
$js4 = "onmouseover=" ascii nocase
$js5 = "onfocus=" ascii nocase
$tag1 = "<script" ascii nocase
$tag2 = "<svg" ascii nocase
$tag3 = "<img" ascii nocase
$enc1 = "<script" ascii nocase
$enc2 = "%3cscript" ascii nocase
condition:
uint16(0) == 0x3C3F or filesize < 64KB
and 1 of ($attr_break*) and 1 of ($js*)
or 1 of ($tag*) and 1 of ($js*)
or 1 of ($enc*)
}
Suricata IDS Rule
alert http any any -> any any (msg:"CVE-2026-109653 ERPNext Stored XSS Attribute-Context Payload Injection Attempt"; flow:established,to_server; http.method; content:"POST"; http.uri; content:"/api/"; nocase; http.request_body; content:"\"><"; nocase; http.request_body; content:"onerror="; nocase; http.request_body; content:"<script"; nocase; threshold: type both, track by_src, count 1, seconds 60; classtype:web-application-attack; reference:cve,2026-109653; reference:url,nvd.nist.gov/vuln/detail/CVE-2026-109653; sid:2026109653; rev:1;)
alert http any any -> any any (msg:"CVE-2026-109653 ERPNext Attribute-Context SVX/IMG Event Handler Injection"; flow:established,to_server; http.method; content:"POST"; http.uri; content:"/api/"; nocase; pcre:"/(<svg|<img|javascript:|onload=|onmouseover=)/i"; pcre:"/(\\\"\s*>|'\s*>\s*<)/"; classtype:web-application-attack; reference:cve,2026-109653; sid:2026109654; rev:1;)
Elastic Detection
sequence by user.id with maxspan=5m
[ network where event.action == "request"
and http.request.method in ("POST", "PUT")
and startsWith( url.path, "/api/resource/" ) ]
[ network where event.action == "request"
and http.request.method in ("POST", "PUT")
and startsWith( url.path, "/api/resource/" )
and ( stringContains(http.request.body, "\"><") or
stringContains(http.request.body, "javascript:") or
stringContains(http.request.body, "onerror=") or
stringContains(http.request.body, "<svg") or
stringContains(http.request.body, "<script") ) ]
Splunk SPL Query
index=web OR index=erpnext sourcetype=erpnext:access OR sourcetype=nginx:plus:access
http_method=POST
| where match(uri, "^/api/")
| eval body=coalesce(request_body, http_request_body, "")
| eval attr_break=if(match(body, "(\"|')>"), 1, 0)
| eval js_exec=if(match(body, "(?i)(javascript:|onerror=|onload=|onmouseover=|onfocus=)"), 1, 0)
| eval tag_inj=if(match(body, "(?i)(<script|<svg|<img)"), 1, 0)
| where attr_break=1 AND (js_exec=1 OR tag_inj=1)
| stats count min(_time) as first_seen max(_time) as last_seen values(uri) as targets values(src_ip) as source_ips by user
| where count >= 1
| sort - count
| table user, count, first_seen, last_seen, targets, source_ips
Wazuh OSSEC Rule
<group name="erpnext,web,attack,cve_2026_109653">
<rule id="1096530" level="12">
<if_sid>31100,31101,31103,31151</if_sid>
<match>POST</match>
<match>/api/</match>
<regex type="pcre2">(?i)(\"|')>\s*<|javascript:|onerror=|onload=|onmouseover=|onfocus=</regex>
<description>CVE-2026-109653 ERPNext stored XSS attribute-context payload submitted to record field</description>
<mitre>
<id>T1059.007</id>
</mitre>
<group>cve_2026_109653,stored_xss,</group>
</rule>
<rule id="1096531" level="10">
<if_sid>1096530</if_sid>
<match>/api/resource/</match>
<description>CVE-2026-109653 ERPNext XSS payload injected via resource record update</description>
<mitre>
<id>T1059.007</id>
</mitre>
<group>cve_2026_109653,stored_xss,</group>
</rule>
</group>
Mitigation & Patch Guidance
Patch confidence: 0/4 (UNPATCHED — no patch evidence from any tracked source). No vendor fix or workaround was provided in the intelligence data. The NVD description references version boundaries (before 15.119.0 and 16.x before 16.31.0), but this has not been corroborated by a vendor advisory, and no patch source is tracked — treat the environment as unpatched until verified against an authoritative Frappe advisory.
Immediate mitigations (compensating controls while unpatched)
- Restrict write access: audit and minimize which low-privilege roles can create/edit the record fields that are rendered into HTML attributes. Least privilege reduces the pool of users able to store a payload.
- Egress and CSP: deploy a strict Content-Security-Policy that disallows inline script and untrusted script sources (
script-src 'self'plus nonces/hashes). CSP with inline-script blocking neutralizes most stored-XSS execution even if the attribute escaping flaw remains. - Output-side protection: place a WAF/API gateway in front of ERPNext and block request bodies containing HTML attribute-break and JavaScript event-handler patterns (see detection rules) on
/api/write paths. - Session hardening: mark session cookies
HttpOnlyandSecure, andSameSite=Strictwhere feasible, to blunt cookie theft from injected scripts. - Network exposure: move ERPNext behind VPN/zero-trust access; do not expose administrative or record-editing pages directly to the internet.
- Monitoring: enable the Sigma/Suricata/Splunk/Wazuh detections above and alert on post-injection session anomalies and privilege changes.
Patch / upgrade steps
- Continuously monitor the official Frappe ERPNext release channels and the NVD entry for CVE-2026-109653 for a verified advisory.
- When a vendor fix is confirmed, upgrade to the first fixed release at or above the corrected 15.x and 16.x lines and validate by testing the affected record/page rendering in a staging environment.
- Because patch confidence is 0/4, do not assume any current release is fixed solely on the basis of the version numbers in the description; confirm against the vendor advisory.
Long-term hardening
- Apply context-aware output encoding as a code standard: attribute contexts, JavaScript contexts, and HTML-body contexts each require distinct escaping. Adopt a templating/auto-escaping framework that encodes by default.
- Add server-side input validation and sanitization on record fields that may be rendered in markup.
- Adopt a Content-Security-Policy as a standing control, not an incident response measure.
- Use Trusted Types where supported to eliminate DOM-XSS sinks.
- Run regular authenticated and unauthenticated XSS testing against ERPNext record-edit and record-view flows, and include attribute-context injection in regression suites.
- Maintain asset inventory and version tracking for ERPNext instances and subscribe to vendor security bulletins.
References
- NVD — CVE-2026-109653: https://nvd.nist.gov/vuln/detail/CVE-2026-109653
- CWE-79 — Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting'): https://cwe.mitre.org/data/definitions/79.html
- FIRST EPSS (not yet scored for this CVE as of this report): https://api.first.org/data/v1/epss?cve=CVE-2026-109653
- CISA Known Exploited Vulnerabilities Catalog (CVE-2026-109653 not listed): https://www.cisa.gov/known-exploited-vulnerabilities-catalog
- OWASP Cross Site Scripting Prevention Cheat Sheet (context-aware output encoding): https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
Threat actor / exploit-in-the-wild status: No public PoC, no Nuclei template, no exploit code, and no CISA KEV listing were identified in the provided intelligence. No threat actor campaign is currently associated with CVE-2026-109653 in the available data.
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.