CVE-2026-109604
Executive Summary
CVE-2026-109604 is a stored cross-site scripting (XSS) vulnerability in Frappe ERPNext affecting versions before 15.112.0 and 16.x before 16.23.0. The flaw exists because a "tool view" interpolates stored record names into markup without output escaping, allowing an authenticated user who can create such records to embed a malicious name that executes JavaScript in the session of any user who later opens that tool. With a CVSS base score of 7.3 (High), exploitation requires low privileges and user interaction, but delivers high confidentiality and integrity impact across the affected ERP deployment.
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 vulnerability is classified as CWE-79 (Improper Neutralization of Input During Web Page Generation, commonly "Cross-Site Scripting") and manifests as the stored (persistent) subtype. Per the NVD description, a "tool view" within ERPNext interpolates the names of stored records into generated markup without escaping them. Because record names are attacker-controllable at creation time and are persisted server-side, the malicious content survives in the application database and is rendered later — not only to the creator, but to any user who opens the affected tool view.
Two properties of the flaw drive its severity:
- Persistence and fan-out. Unlike reflected XSS, the payload lives in the record itself. The attacker injects once and the script executes each time any authorized user opens the tool. This decouples attacker effort from victim count and makes timing unpredictable — the victim may open the tool days after injection.
- Trusted-origin execution. The script runs in the origin of the ERPNext instance with the victim's authenticated session context. It is not sandboxed by any browser control, so it inherits all cookies, tokens, and page DOM access granted to the victim session.
Attack surface: the affected "tool" view reachable by authenticated users, and the record-creation path that writes the malicious name. The CVSS vector (AV:N, AC:L, PR:L, UI:R) confirms the vector is network-reachable, requires only low-privileged authenticated access to create the record, and requires a victim to open the crafted view (UI:R). Scope is Unchanged — the vulnerable component and the impacted component are the same ERPNext application. Only Confidentiality and Integrity are rated High; Availability is None, consistent with script execution that affects data and session integrity but does not directly deny service.
No patch commit, vendor advisory text, affected package manifest, or public proof-of-concept is available from the tracked sources for this CVE. Where the description is silent, this report describes the vulnerability class and mechanism rather than inventing specific function names, endpoints, file paths, or parameters. No public PoC is available at time of writing; the exploitation chain below is inferred from the stored-XSS vulnerability class and the explicit description facts.
Note on scope: MITRE's CWE-79 maps to T1059.007 (JavaScript/JScript) in ATT&CK, which is the tactic reflected above. Some taxonomies instead cite T1189 (Drive-by Compromise) for browser-delivered script execution; T1059.007 is used here because the payload is JavaScript executed in the victim's browser session.
Exploitation Scenarios
The following chain is built strictly from the facts stated in the NVD description. No implementation-specific identifiers are invented.
Step 1 — Reconnaissance / target identification. An attacker identifies an internet-facing or internally reachable ERPNext instance running a version below 15.112.0 or 16.x below 16.23.0. Version fingerprinting can be performed via the ERPNext login/desk page, response headers, or static asset fingerprints. The attacker must possess at least one authenticated account capable of creating the relevant record type.
Step 2 — Triggering the specific flaw. Using the authenticated low-privileged account, the attacker creates a record whose name field contains a JavaScript payload. Because the tool view later interpolates that stored name into markup without escaping, the malicious value is persisted in the application database. No special privileges beyond record-creation rights are required per PR:L.
Step 3 — Payload / execution at the vulnerability-class level. The payload, embedded in the record name, is rendered unescaped into the tool view. When any user — including a higher-privileged user such as an administrator or finance user — opens that tool, their browser parses the injected markup as part of the page and executes the JavaScript in the ERPNext origin. At the class level, the payload would typically perform actions the victim's session is authorized to do: reading page content, issuing same-origin authenticated requests, exfiltrating data to an attacker-controlled endpoint, or modifying records. Specific payload strings are not provided in the source data and are not fabricated here.
Step 4 — Post-exploitation impact. Executed JavaScript inherits the victim's authenticated ERPNext session. Depending on the victim's role, consequences include theft of session tokens or sensitive business data (Confidentiality: High), and unauthorized creation/modification of records via the victim's permissions (Integrity: High), matching the CVSS vector. Because the payload remains stored, each subsequent view of the tool re-triggers execution, and any number of users may be affected.
No public exploit, Nuclei template, or Metasploit module is available for this CVE as of writing; EPSS has not yet scored it. Exploitation in the wild has not been reported and CISA KEV does not list it.
Impact Assessment
ERPNext is an open-source enterprise resource planning platform handling finance, HR, inventory, CRM, and manufacturing data. A stored XSS in a trusted authenticated view is significant because it grants script execution inside a session that typically holds broad business privileges.
- Confidentiality (High): Script running in the victim session can read and exfiltrate any data the victim can access — financial records, customer data, employee information, and possibly API keys or tokens exposed to the page.
- Integrity (High): The attacker can use the victim's session to create, modify, or delete records within the victim's authorization scope, potentially corrupting ledgers or approvals.
- Availability (None): The vector assigns no availability impact.
- Privilege escalation path: If an administrator opens the affected tool, the attacker effectively obtains administrative-level session access — a low-privileged account (PR:L) can pivot into a far more privileged context. This is the primary blast-radius concern.
- Persistence: Stored payload re-executes on every view, giving durable access without repeated effort, and the record must be deleted or sanitized to fully eradicate it.
Blast radius is the specific ERPNext instance and every user who opens the affected tool view; the attacker controls timing by choosing when to plant the record and by what triggers victim viewing.
Detection Guidance
Sigma Rule
title: Suspected Stored XSS via ERPNext Tool View Record Name
id: 3b1e9f2a-7c4d-4a8e-9b6f-109604cve01
status: experimental
description: Detects creation/modification of ERPNext records whose name field contains HTML/JS markup, consistent with stored XSS (CVE-2026-109604).
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-109604
author: valtersit.com
date: 2026/01/01
logsource:
product: erpnext
service: audit
detection:
selection_event:
event.action|contains:
- "create"
- "update"
selection_payload:
record.name|contains:
- "<script"
- "</script"
- "onerror="
- "onload="
- "javascript:"
- "<img"
- "<svg"
- "<iframe"
condition: selection_event and selection_payload
fields:
- user.name
- record.name
- source.ip
falsepositives:
- Legitimate record names that contain angle brackets or markup-like text
level: high
tags:
- attack.t1059.007
- cwe.79
YARA Rule
rule CVE_2026_109604_ERPNext_Stored_XSS
{
meta:
description = "Detects stored XSS payloads in ERPNext record names / tool view markup (CVE-2026-109604)"
author = "valtersit.com"
date = "2026-01-01"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-109604"
cve = "CVE-2026-109604"
severity = "high"
strings:
$sc1 = "<script" nocase
$sc2 = "</script" nocase
$ev1 = "onerror=" nocase
$ev2 = "onload=" nocase
$ev3 = "onmouseover=" nocase
$js1 = "javascript:" nocase
$tag1 = "<svg" nocase
$tag2 = "<iframe" nocase
$tag3 = "<img" nocase
$erp1 = "erpnext" nocase
$erp2 = "frappe" nocase
condition:
filesize < 2MB and
(2 of ($sc*) or 2 of ($ev*) or $js1) and
(1 of ($tag*) or 1 of ($erp*))
}
Suricata IDS Rule
alert http any any -> any any (msg:"CVE-2026-109604 ERPNext Stored XSS Record Name Payload"; flow:to_server,established; http.method; content:"POST"; http.request_body; content:"<script"; nocase; http.request_body; content:"onerror="; nocase; http.request_body; content:"erpnext"; nocase; reference:cve,2026-109604; reference:url,nvd.nist.gov/vuln/detail/CVE-2026-109604; classtype:web-application-attack; sid:2026109604; rev:1;)
alert http any any -> any any (msg:"CVE-2026-109604 ERPNext Stored XSS Event Handler Injection"; flow:to_server,established; http.request_body; pcre:"/(onerror|onload|onmouseover)\s*=/i"; http.request_body; content:"<svg"; nocase; reference:cve,2026-109604; classtype:web-application-attack; sid:2026109605; rev:1;)
Elastic Detection
sequence by user.name, source.ip with maxspan=30s
[any where event.action in ("create", "update") and
wildcard(record.name, "*<script*", "*onerror=*", "*onload=*", "*javascript:*")]
Splunk SPL Query
index=erpnext sourcetype=erpnext:audit (event.action=create OR event.action=update)
| eval suspicious=if(match(record.name, "(?i)(<script|</script|onerror=|onload=|onmouseover=|javascript:|<svg|<iframe|<img)"), 1, 0)
| where suspicious=1
| stats count min(_time) as first_seen max(_time) as last_seen values(record.name) as payload by user.name, source.ip, dest
| sort - count
Wazuh OSSEC Rule
<group name="erpnext,web,attack,">
<rule id="109604" level="12">
<decoded_as>json</decoded_as>
<field name="event.action">create|update</field>
<field name="record.name" type="pcre2">(?i)(<script|</script|onerror=|onload=|onmouseover=|javascript:|<svg|<iframe|<img)</field>
<description>CVE-2026-109604: Possible stored XSS payload in ERPNext record name by $(user.name) from $(source.ip)</description>
<mitre>
<id>T1059.007</id>
</mitre>
<group>cve_2026_109604,xss,</group>
</rule>
</group>
Mitigation & Patch Guidance
Patch confidence: 0/4 (UNPATCHED — no patch evidence from any tracked source). No vendor fix, workaround, or patch reference is available from the tracked data. The version boundaries stated in the NVD description (< 15.112.0 and 16.x < 16.23.0) indicate the fixed releases, but no commit or advisory has been confirmed.
1) Immediate mitigations (until a verified patch is applied):
- Restrict who can create or edit the record types whose names populate the affected tool view; apply least privilege so low-trust accounts cannot create records that feed that view.
- Enforce output encoding of record names at render time, or sanitize/escape stored names before they are interpolated into markup, as a compensating control.
- Deploy a Content-Security-Policy that disallows inline script and restricts script-src to trusted origins to reduce XSS execution impact.
- Add WAF/reverse-proxy rules to block requests carrying HTML/JS markup in record-name fields (see detection rules above).
- Monitor and audit creation/modification of records whose names contain markup characters; treat any such event as suspicious.
2) Patch / upgrade steps:
- Upgrade ERPNext to 15.112.0 or later on the 15.x branch, or to 16.23.0 or later on the 16.x branch — the fixed versions named in the NVD description.
- Verify the upgrade actually deployed by checking the reported version after update; because no official advisory/commit is confirmed, validate the fix with a controlled XSS test in a staging environment before relying on it in production.
- Back up the database and test the upgrade on staging first, given the ERP data-integrity implications.
3) Long-term hardening:
- Adopt a secure-by-default templating policy that contextually encodes all user/record-controlled values; add regression tests that fail on unescaped interpolation.
- Instantiate a system-wide Content-Security-Policy and enable HTTPOnly/Secure/SameSite on session cookies to blunt session-theft from XSS.
- Integrate SAST/DAST checks for CWE-79 into CI/CD and run periodic dependency/version scans against the ERPNext release stream.
- Maintain an audit trail and alerting on record-name markup (see Detection Guidance) as a durable compensating detection.
References
- NVD — CVE-2026-109604: https://nvd.nist.gov/vuln/detail/CVE-2026-109604
- Frappe ERPNext project / release repository (verify fixed versions 15.112.0 and 16.23.0): https://github.com/frappe/erpnext
- CWE-79 — Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting'): https://cwe.mitre.org/data/definitions/79.html
- MITRE ATT&CK T1059.007 — Command and Scripting Interpreter: JavaScript: https://attack.mitre.org/techniques/T1059/007/
- CISA Known Exploited Vulnerabilities Catalog (this CVE is not listed as of writing): https://www.cisa.gov/known-exploited-vulnerabilities-catalog
No threat actor campaign or exploit-in-the-wild evidence is associated with CVE-2026-109604 in the provided data; no public PoC, Nuclei template, or exploit code is available, and the CVE is not listed in CISA KEV.
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.