CSIRTS // UNIFIED SECURITY ADVISORY FEEDSYS ● ONLINE · POWERED BY INTELFUSIONS.COM

GHSA-xf7x-x43h-rpqh: json_repair: Circular JSON Schema `$ref` causes unbounded CPU DoS

highCVSS 7.5
Circular JSON Schema $ref causes unbounded CPU DoS in json_repair Summary SchemaRepairer.resolve_schema() in json_repair follows JSON Schema $ref pointers in an unbounded while loop without any cycle detection. An attacker who can supply a schema containing a self-referencing $ref (e.g., via the demo Flask API or any application that passes untrusted input to loads(..., schema=...)), can cause a worker process to spin indefinitely on CPU, resulting in a complete denial of service. No authentication is required against the public demo API. The vulnerability is confirmed reproducible at CVSS 7.5 (High). Details SchemaRepairer.resolve_schema() at src/json_repair/schema_repair.py:184–190 resolves $ref chains using a plain while loop: src/json_repair/schema_repair.py:184-190 schema_dict = cast("dict[str, Any]", schema) while "$ref" in schema_dict: ref = schema_dict["$ref"] resolved = self._resolve_ref(ref) if isinstance(resolved, bool): return resolved schema_dict = resolved _resolve_ref() at src/json_repair/schema_repair.py:654–665 always resolves references relative to self.root_schema, which is initialised from the caller-supplied schema (src/json_repair/schema_repair.py:130). When the schema contains a circular reference such as: {"$ref": "#/definitions/a", "definitions": {"a": {"$ref": "#/definitions/a"}}} _resolve_ref() returns the same dict object on every iteration, so "$ref" in schema_dict is always True and the loop never terminates. The vulnerable sink is reachable without authentication through the demo Flask API: docs/app.py:14, 21-36 data = request.get_json() schema = data.get("schema") if schema is not None and not isinstance(schema, (dict, bool)): raise ValueError("schema must be a JSON object or boolean.") ... if schema is not None: loads_kwargs["schema"] = schema parsed_json = loads(malformed_json, **loads_kwargs) The only guard is a top-level isinstance(dict, bool) check; there is no $ref depth limit, no visited-set, and no timeout enforced

Details

Source
GitHub Security Advisories (INTL · database · site)
Severity
high — CVSS 7.5
Published
2026-07-13
Last updated
2026-07-13
Exploitation
Not in CISA KEV at last sync

Original advisory: https://github.com/advisories/GHSA-xf7x-x43h-rpqh

More from GitHub Security Advisories