Skip to content
Heist/ feed
Back to feed
LowFix available

djust: Arbitrary absolute-path file read in the find_handlers_for_template MCP tool

Type: advisorySources: OSV

### Affected version / file / line Version: djust v1.1.4 (latest release, published 2026-09-23). File: python/djust/mcp/server.py:354-433 (MCP tool find_handlers_for_template). Confirmed identical on the commit used for triage, a7e4fafd1667b4db0b1465652d4a63cb17117a07. ### Description ``` @mcp.tool() def find_handlers_for_template(template_path: str) -> str: """ Args: template_path: Either a logical template name (e.g. 'demos/counter.html' — what you'd pass to `render`) OR an absolute filesystem path. Both are searched. """ ... resolved_path: str | None = None if os.path.isabs(template_path) and os.path.isfile(template_path): resolved_path = template_path else: ... # logical-name resolution via Django's template loader ... with open(resolved_path, "r", encoding="utf-8", errors="replace") as f: source = f.read() handler_names_in_template = sorted({m.group(2) for m in dj_event_attr_re.finditer(source)}) ``` When template_path is an absolute path to an existing file, it is used directly, with no confinement to the project/template directories — no realpath() + prefix check, no allowlist. open(resolved_path, ...) then reads the file. This is inconsistent with the sibling tool in the same file (loaddata, ~line 290-303), which explicitly rejects paths outside the project directory for its own path-like parameter: ``` candidate = os.path.realpath(...) if base_dir and not candidate.startswith(os.path.realpath(str(base_dir))): return json.dumps({"error": f"fixture path '{p}' resolves

Products
djust
Affected versions
0.9.0, 0.9.1, 0.9.2, 0.9.4, 0.9.5, 0.9.6, 0.9.7, 1.0.0, 1.0.0rc11, 1.0.1, 1.0.2, 1.0.3, 1.0.4, 1.0.5, 1.0.6, 1.0.7, 1.0.8, 1.0.9, 1.1.0, 1.1.1, 1.1.2, 1.1.3, 1.1.4, 1.1.5, 1.1.6, 1.2.0, 1.2.1, 1.2.1rc1, 1.2.1rc2, 1.2.2, 1.2.3, 1.3.0rc4, 1.3.0rc5, 1.3.0rc6, 1.3.0rc7
Fixed versions
1.0.10, 1.1.7, 1.2.4, 1.3.0rc8
CVEs
CVE-2026-113731
Confirmed fixed CVEs
Not specified
Updated in this feed
31 Oct 2026, 15:36 UTC · Revision 1

Source evidence

djust: Arbitrary absolute-path file read in the find_handlers_for_template MCP tool

core-osv · Original source

Published 21 Oct 2026, 17:21 UTC

### Affected version / file / line Version: djust v1.1.4 (latest release, published 2026-09-23). File: python/djust/mcp/server.py:354-433 (MCP tool find_handlers_for_template). Confirmed identical on the commit used for triage, a7e4fafd1667b4db0b1465652d4a63cb17117a07. ### Description ``` @mcp.tool() def find_handlers_for_template(template_path: str) -> str: """ Args: template_path: Either a logical template name (e.g. 'demos/counter.html' — what you'd pass to `render`) OR an absolute filesystem path. Both are searched. """ ... resolved_path: str | None = None if os.path.isabs(template_path) and os.path.isfile(template_path): resolved_path = template_path else: ... # logical-name resolution via Django's template loader ... with open(resolved_path, "r", encoding="utf-8", errors="replace") as f: source = f.read() handler_names_in_template = sorted({m.group(2) for m in dj_event_attr_re.finditer(source)}) ``` When template_path is an absolute path to an existing file, it is used directly, with no confinement to the project/template directories — no realpath() + prefix check, no allowlist. open(resolved_path, ...) then reads the file. This is inconsistent with the sibling tool in the same file (loaddata, ~line 290-303), which explicitly rejects paths outside the project directory for its own path-like parameter: ``` candidate = os.path.realpath(...) if base_dir and not candidate.startswith(os.path.realpath(str(base_dir))): return json.dumps({"error": f"fixture path '{p}' resolves

osv:GHSA-r57g-mc79-8hj2

djust

Fixed versions: 1.0.10

djust

Fixed versions: 1.1.7

djust

Fixed versions: 1.2.4

djust

Fixed versions: 1.3.0rc8

Complete source record
{
  "id": "373b0cb1a004a2ccb88760aa43c1970e60d5bd736a151a00f6e89b07f80191c1",
  "url": "https://osv.dev/vulnerability/GHSA-r57g-mc79-8hj2",
  "method": "structured",
  "payload": {
    "kind": "advisory",
    "title": "djust: Arbitrary absolute-path file read in the find_handlers_for_template MCP tool",
    "summary": "### Affected version / file / line Version: djust v1.1.4 (latest release, published 2026-09-23). File: python/djust/mcp/server.py:354-433 (MCP tool find_handlers_for_template). Confirmed identical on the commit used for triage, a7e4fafd1667b4db0b1465652d4a63cb17117a07. ### Description ``` @mcp.tool() def find_handlers_for_template(template_path: str) -> str: \"\"\" Args: template_path: Either a logical template name (e.g. 'demos/counter.html' — what you'd pass to `render`) OR an absolute filesystem path. Both are searched. \"\"\" ... resolved_path: str | None = None if os.path.isabs(template_path) and os.path.isfile(template_path): resolved_path = template_path else: ... # logical-name resolution via Django's template loader ... with open(resolved_path, \"r\", encoding=\"utf-8\", errors=\"replace\") as f: source = f.read() handler_names_in_template = sorted({m.group(2) for m in dj_event_attr_re.finditer(source)}) ``` When template_path is an absolute path to an existing file, it is used directly, with no confinement to the project/template directories — no realpath() + prefix check, no allowlist. open(resolved_path, ...) then reads the file. This is inconsistent with the sibling tool in the same file (loaddata, ~line 290-303), which explicitly rejects paths outside the project directory for its own path-like parameter: ``` candidate = os.path.realpath(...) if base_dir and not candidate.startswith(os.path.realpath(str(base_dir))): return json.dumps({\"error\": f\"fixture path '{p}' resolves ",
    "evidence": "osv:GHSA-r57g-mc79-8hj2",
    "products": [
      {
        "name": {
          "value": "djust",
          "evidence": "/affected/0/package/name"
        },
        "prerequisites": [],
        "fixed_versions": [
          {
            "value": "1.0.10",
            "evidence": "/affected/0/ranges"
          }
        ],
        "affected_versions": [
          {
            "value": "0.9.0",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "0.9.1",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "0.9.2",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "0.9.4",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "0.9.5",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "0.9.6",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "0.9.7",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "1.0.0",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "1.0.0rc11",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "1.0.1",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "1.0.2",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "1.0.3",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "1.0.4",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "1.0.5",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "1.0.6",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "1.0.7",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "1.0.8",
            "evidence": "/affected/0/versions"
          },
          {
            "value": "1.0.9",
            "evidence": "/affected/0/versions"
          }
        ]
      },
      {
        "name": {
          "value": "djust",
          "evidence": "/affected/1/package/name"
        },
        "prerequisites": [],
        "fixed_versions": [
          {
            "value": "1.1.7",
            "evidence": "/affected/1/ranges"
          }
        ],
        "affected_versions": [
          {
            "value": "1.1.0",
            "evidence": "/affected/1/versions"
          },
          {
            "value": "1.1.1",
            "evidence": "/affected/1/versions"
          },
          {
            "value": "1.1.2",
            "evidence": "/affected/1/versions"
          },
          {
            "value": "1.1.3",
            "evidence": "/affected/1/versions"
          },
          {
            "value": "1.1.4",
            "evidence": "/affected/1/versions"
          },
          {
            "value": "1.1.5",
            "evidence": "/affected/1/versions"
          },
          {
            "value": "1.1.6",
            "evidence": "/affected/1/versions"
          }
        ]
      },
      {
        "name": {
          "value": "djust",
          "evidence": "/affected/2/package/name"
        },
        "prerequisites": [],
        "fixed_versions": [
          {
            "value": "1.2.4",
            "evidence": "/affected/2/ranges"
          }
        ],
        "affected_versions": [
          {
            "value": "1.2.0",
            "evidence": "/affected/2/versions"
          },
          {
            "value": "1.2.1",
            "evidence": "/affected/2/versions"
          },
          {
            "value": "1.2.1rc1",
            "evidence": "/affected/2/versions"
          },
          {
            "value": "1.2.1rc2",
            "evidence": "/affected/2/versions"
          },
          {
            "value": "1.2.2",
            "evidence": "/affected/2/versions"
          },
          {
            "value": "1.2.3",
            "evidence": "/affected/2/versions"
          }
        ]
      },
      {
        "name": {
          "value": "djust",
          "evidence": "/affected/3/package/name"
        },
        "prerequisites": [],
        "fixed_versions": [
          {
            "value": "1.3.0rc8",
            "evidence": "/affected/3/ranges"
          }
        ],
        "affected_versions": [
          {
            "value": "1.3.0rc4",
            "evidence": "/affected/3/versions"
          },
          {
            "value": "1.3.0rc5",
            "evidence": "/affected/3/versions"
          },
          {
            "value": "1.3.0rc6",
            "evidence": "/affected/3/versions"
          },
          {
            "value": "1.3.0rc7",
            "evidence": "/affected/3/versions"
          }
        ]
      }
    ],
    "severity": "low",
    "structured": {
      "id": "GHSA-r57g-mc79-8hj2",
      "aliases": [
        "CVE-2026-113731",
        "GHSA-r57g-mc79-8hj2"
      ],
      "metrics": [
        {
          "type": "CVSS_V3",
          "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N"
        }
      ],
      "affected": [
        {
          "ranges": [
            {
              "type": "ECOSYSTEM",
              "events": [
                {
                  "introduced": "0.9.0"
                },
                {
                  "fixed": "1.0.10"
                }
              ]
            }
          ],
          "package": {
            "name": "djust",
            "purl": "pkg:pypi/djust",
            "ecosystem": "PyPI"
          },
          "versions": [
            "0.9.0",
            "0.9.1",
            "0.9.2",
            "0.9.4",
            "0.9.5",
            "0.9.6",
            "0.9.7",
            "1.0.0",
            "1.0.0rc11",
            "1.0.1",
            "1.0.2",
            "1.0.3",
            "1.0.4",
            "1.0.5",
            "1.0.6",
            "1.0.7",
            "1.0.8",
            "1.0.9"
          ],
          "database_specific": {
            "source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-r57g-mc79-8hj2/GHSA-r57g-mc79-8hj2.json",
            "last_known_affected_version_range": "<= 1.0.9"
          }
        },
        {
          "ranges": [
            {
              "type": "ECOSYSTEM",
              "events": [
                {
                  "introduced": "1.1.0"
                },
                {
                  "fixed": "1.1.7"
                }
              ]
            }
          ],
          "package": {
            "name": "djust",
            "purl": "pkg:pypi/djust",
            "ecosystem": "PyPI"
          },
          "versions": [
            "1.1.0",
            "1.1.1",
            "1.1.2",
            "1.1.3",
            "1.1.4",
            "1.1.5",
            "1.1.6"
          ],
          "database_specific": {
            "source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-r57g-mc79-8hj2/GHSA-r57g-mc79-8hj2.json",
            "last_known_affected_version_range": "<= 1.1.6"
          }
        },
        {
          "ranges": [
            {
              "type": "ECOSYSTEM",
              "events": [
                {
                  "introduced": "1.2.0.dev0"
                },
                {
                  "fixed": "1.2.4"
                }
              ]
            }
          ],
          "package": {
            "name": "djust",
            "purl": "pkg:pypi/djust",
            "ecosystem": "PyPI"
          },
          "versions": [
            "1.2.0",
            "1.2.1",
            "1.2.1rc1",
            "1.2.1rc2",
            "1.2.2",
            "1.2.3"
          ],
          "database_specific": {
            "source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-r57g-mc79-8hj2/GHSA-r57g-mc79-8hj2.json",
            "last_known_affected_version_range": "<= 1.2.3"
          }
        },
        {
          "ranges": [
            {
              "type": "ECOSYSTEM",
              "events": [
                {
                  "introduced": "1.3.0.dev0"
                },
                {
                  "fixed": "1.3.0rc8"
                }
              ]
            }
          ],
          "package": {
            "name": "djust",
            "purl": "pkg:pypi/djust",
            "ecosystem": "PyPI"
          },
          "versions": [
            "1.3.0rc4",
            "1.3.0rc5",
            "1.3.0rc6",
            "1.3.0rc7"
          ],
          "database_specific": {
            "source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-r57g-mc79-8hj2/GHSA-r57g-mc79-8hj2.json",
            "last_known_affected_version_range": "<= 1.3.0rc7"
          }
        }
      ],
      "modified": "2026-10-21T17:35:19.934118290Z",
      "provider": "osv",
      "references": [
        "https://github.com/djust-org/djust/security/advisories/GHSA-r57g-mc79-8hj2",
        "https://nvd.nist.gov/vuln/detail/CVE-2026-113731",
        "https://github.com/djust-org/djust/commit/45a5045793ebe7c9c2df86b0ad34275af6822619",
        "https://github.com/djust-org/djust/commit/744bccf699c65c815d9379b36236a7c5592a339b",
        "https://github.com/djust-org/djust/commit/85eed7caaf620bdb08986f2f3bb79432c0d3d715",
        "https://github.com/djust-org/djust/commit/a62caf6b4ef540ad688d4dfdfa407ff914c78728",
        "https://github.com/djust-org/djust",
        "https://github.com/djust-org/djust/releases/tag/v1.0.10",
        "https://github.com/djust-org/djust/releases/tag/v1.1.7",
        "https://github.com/djust-org/djust/releases/tag/v1.2.4",
        "https://github.com/djust-org/djust/releases/tag/v1.3.0rc8"
      ],
      "provider_metadata": {
        "cwe_ids": [
          "CWE-22"
        ],
        "severity": "LOW",
        "github_reviewed": true,
        "nvd_published_at": "2026-10-20T22:19:30Z",
        "github_reviewed_at": "2026-10-21T17:21:15Z"
      }
    },
    "related_cves": [
      {
        "value": "CVE-2026-113731",
        "evidence": "/aliases"
      }
    ],
    "security_relevant": true,
    "severity_evidence": "/database_specific/severity"
  },
  "source_id": "core-osv",
  "document_id": 397806,
  "published_at": "2026-10-21T17:21:15+00:00"
}