Listen to this Post
A context safety grant was inherited by a template binding that never earned it, so rebinding a name the view had marked safe left the mark attached to the new, attacker-controlled value. djust’s context safety channel is keyed by name, not by value. Every bind copied the value and left the grant in place. The view marks a value as safe using mark_safe('<b>trusted</b>'). When a template later rebinds that same name with untrusted input using {% with p=user_input %}{{ p }}{% endwith %}, djust emits the attacker-controlled value without escaping, executing the payload, while Django correctly escapes it. This affects eight distinct bind shapes: `{% with %}` rebinding a marked name, `{% with %}` descendant of a rebound name, `{% with %}` binding over a marked name, `{% for %}` loop variable, `{% for %}` descendant, `{% for %}` tuple unpacking, {% include … with %}, and assign tags. No filter chain and no `|safe` anywhere in the template is required. The precondition is that the application marked some value safe under a name that a template later rebinds — an ordinary pattern, since a view commonly marks trusted markup safe and templates commonly reuse short names such as p, `item` or row. The impact is stored or reflected XSS in any djust application that combines `mark_safe` (or any framework path that grants a context key safety) with a template that rebinds that name. Exploitation requires no unusual template construct. Patches are available in 1.1.2 and 1.2.0 (main). The rule is that a bind replaces the grant rather than inheriting one. Not fixed in 1.1.2, and tracked for 1.2.0, are two over-escaping cases where a grant fails to travel with a value that legitimately carries one ({% with body=post.text|linebreaks %}, and `mark_safe` reaching a template through `dict.values` / dict.items). Both escape more than Django rather than less, so neither is a leak. Before upgrading, avoid reusing a context name for both mark_safe‘d content and untrusted input, and avoid rebinding such a name in {% with %}, {% for %}, `{% include … with %}` or an assign tag. This was found while preparing the 1.1.1 security release: the reproducer published in GHSA-9395-2g46-rj3f was run against the built 1.1.1 artifact before that advisory was published, and proved the class was still live.
DailyCVE Form:
Platform: djust
Version: <= 1.1.1
Vulnerability: context grant inheritance
Severity: High
date: 2026-08-30
Prediction: 2026-09-17
What Undercode Say:
pip install djust==1.1.1 python -c "import djust; print(djust.<strong>version</strong>)"
vulnerable view
from django.utils.safestring import mark_safe
def index(request):
return render(request, "index.html", {"p": mark_safe("<b>trusted</b>")})
template index.html
{% with p=user_input %}{{ p }}{% endwith %}
Exploit: (Educational Purposes!)
attacker supplies user_input = '<img src=x onerror=alert(1)>' view marks p safe, template rebinds p with attacker input result: djust emits '<img src=x onerror=alert(1)>' -> executes django emits '<img src=x onerror=alert(1)>'
Protection: from this CVE
- Upgrade to djust 1.1.2 or 1.2.0.
- Avoid reusing a context name for both
mark_safe‘d content and untrusted input. - Avoid rebinding such a name in
{% with %},{% for %}, `{% include … with %}` or an assign tag.
Impact:
Stored or reflected XSS in any djust application that combines `mark_safe` (or any framework path that grants a context key safety) with a template that rebinds that name.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

