CVE-2026-65974 Overview
CVE-2026-65974 is a server-side template injection vulnerability in ERPNext, the open source Enterprise Resource Planning tool built on the Frappe framework. The flaw exists because frappe.render_template is exposed to the Frappe safe execution environment without forcing the restrict_globals parameter. Authenticated users with limited privileges can cross the safe execution permission boundary and achieve remote code execution on the server. The issue affects ERPNext versions prior to 15.111.0 and 16.22.0, and is tracked under [CWE-1336: Improper Neutralization of Special Elements Used in a Template Engine].
Critical Impact
Authenticated low-privilege users can escape the Frappe sandbox through Jinja template injection and execute arbitrary code on the ERPNext server, compromising confidentiality, integrity, and availability.
Affected Products
- ERPNext versions prior to 15.111.0
- ERPNext versions prior to 16.22.0
- Frappe framework render_template utility used by ERPNext
Discovery Timeline
- 2026-08-17 - CVE-2026-65974 published to NVD
- 2026-08-18 - Last updated in NVD database
Technical Details for CVE-2026-65974
Vulnerability Analysis
ERPNext exposes scripting features that run inside Frappe's safe execution sandbox. The sandbox restricts which Python objects and globals scripts can access. However, the frappe.render_template function was made available inside this sandbox without enforcing restrict_globals=True. As a result, an authenticated user with permission to author server scripts, print formats, or notification templates can supply a Jinja template that reaches unrestricted globals. From there, the attacker walks Python object references to reach os, subprocess, or other modules that provide command execution. The flaw allows a scope change (S:C), meaning code executes with the privileges of the Frappe worker process rather than the invoking user.
Root Cause
The render_template function in frappe/utils/jinja.py accepted restrict_globals as a keyword argument that callers inside the safe execution context could override or leave unset. Because the safe execution wrapper did not force the argument, template rendering ran with the full global namespace. This is a classic sandbox escape driven by improper neutralization of template directives [CWE-1336].
Attack Vector
An attacker requires low-privilege authenticated access to a feature that renders user-supplied templates through the sandbox, such as custom server scripts or notifications. The attacker submits a Jinja payload that traverses Python internals to invoke shell commands. Exploitation is network-based and does not require user interaction.
# Patch: frappe/utils/jinja.py - force restrict_globals to be keyword-only
# Source: https://github.com/frappe/frappe/commit/529d190a252863672164d10bfcd91d1de0ac1c7c
-def render_template(template, context=None, is_path=None, safe_render=True, restrict_globals=None):
+def render_template(template, context=None, is_path=None, safe_render=True, *, restrict_globals=None):
"""Render a template using Jinja
:param template: path or HTML containing the jinja template
# Patch: frappe/utils/safe_exec.py - wrap render_template to enforce restrict_globals=True
# Source: https://github.com/frappe/frappe/commit/529d190a252863672164d10bfcd91d1de0ac1c7c
+def safe_render_template(*args, **kwargs):
+ kwargs.pop("restrict_globals", None)
+ return frappe.render_template(*args, restrict_globals=True, **kwargs)
Detection Methods for CVE-2026-65974
Indicators of Compromise
- Frappe worker processes spawning shell utilities such as sh, bash, python, curl, or wget outside of normal deployment workflows.
- Server scripts, print formats, or notification templates containing Jinja expressions that reference __class__, __mro__, __subclasses__, or __globals__.
- Outbound network connections initiated by the Frappe application user to previously unseen IP addresses.
- Unexpected file writes under sites/, apps/, or the operating system tmp directory by the ERPNext service account.
Detection Strategies
- Audit the Server Script, Print Format, Notification, and Web Template DocTypes for records modified by non-administrator users containing template introspection patterns.
- Monitor process ancestry: any child of gunicorn, frappe, or bench executing an interpreter or shell should be flagged.
- Enable Frappe application logs at debug level for the template rendering pipeline and correlate rendering errors with authenticated session IDs.
Monitoring Recommendations
- Ship Frappe application logs and system auditd events to a centralized data lake for correlation across user activity and process execution.
- Alert on new or modified DocType records that carry Jinja payloads referencing Python dunder attributes.
- Track authentication events for accounts that suddenly gain script authoring roles.
How to Mitigate CVE-2026-65974
Immediate Actions Required
- Upgrade ERPNext to version 15.111.0 or 16.22.0 immediately. See the ERPNext v15.111.0 release notes and ERPNext v16.22.0 release notes.
- Review all users assigned the Script Manager, System Manager, or custom roles that grant access to template-authoring DocTypes and revoke where not required.
- Inspect existing server scripts, print formats, and notifications for malicious Jinja payloads before restarting workers.
Patch Information
The fix is delivered through Frappe commit 529d190. The patch makes restrict_globals a keyword-only argument in render_template and introduces safe_render_template in safe_exec.py, which forces restrict_globals=True and strips any caller-supplied override. Full remediation details are published in the GitHub Security Advisory GHSA-w996-r7v3-87wr.
Workarounds
- Restrict template-authoring roles to trusted administrators until the upgrade is applied.
- Place the ERPNext instance behind an authenticated reverse proxy to reduce exposure of authenticated endpoints.
- Enforce network egress filtering on ERPNext application servers to limit the impact of successful template injection.
# Upgrade ERPNext using bench to a fixed release
bench switch-to-branch version-15 frappe erpnext --upgrade
bench update --reset
bench --site all migrate
bench restart
# Verify installed versions include the fix
bench version | grep -E "erpnext|frappe"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

