Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-54911

CVE-2026-54911: UltraJSON Auth Bypass Vulnerability

CVE-2026-54911 is an authentication bypass flaw in UltraJSON that allows malformed UTF-8 sequences to bypass input validation. This article covers the technical details, affected versions, impact, and mitigation.

Published:

CVE-2026-54911 Overview

CVE-2026-54911 is an input validation vulnerability [CWE-20] in UltraJSON (ujson), a high-performance JSON encoder and decoder written in C with bindings for Python 3.7+. Versions prior to 5.13.0 mishandle malformed UTF-8 byte sequences when ujson.dumps(), ujson.dump(), or ujson.encode() is called with the reject_bytes=False option. Instead of rejecting truncated or invalid UTF-8 input, the library silently rewrites those bytes into different Unicode characters. This behavior enables input validation bypass and introduces data integrity issues for any application relying on ujson to faithfully serialize byte strings.

Critical Impact

Applications using reject_bytes=False may pass attacker-controlled byte sequences through ujson and emit silently-modified JSON, breaking integrity guarantees and enabling validation bypass downstream.

Affected Products

  • UltraJSON (ujson) versions prior to 5.13.0
  • Python 3.7+ applications calling ujson.dumps(), ujson.dump(), or ujson.encode() with reject_bytes=False
  • Downstream services that trust ujson output for validation, signing, or replay

Discovery Timeline

  • 2026-06-22 - CVE-2026-54911 published to NVD
  • 2026-06-23 - Last updated in NVD database

Technical Details for CVE-2026-54911

Vulnerability Analysis

UltraJSON exposes a reject_bytes parameter that, when set to False, allows the encoder to accept bytes input and emit a JSON string. The encoder assumes the input is well-formed UTF-8 but does not fully validate continuation bytes or guard against truncated multi-byte sequences. As a result, malformed input is normalized into replacement or substitute Unicode code points rather than rejected. Attackers who can supply bytes to a service that re-serializes them with ujson can produce output that differs from the input while still being treated as valid by validators that ran on the original bytes.

Root Cause

The defect lives in the UTF-8 decoding paths of src/ujson/lib/ultrajsondec.c and src/ujson/lib/ultrajsonenc.c. The 2-byte UTF-8 branch did not verify that a continuation byte was present and that it carried the expected 10xxxxxx bit pattern. The encoder also failed to require at least two bytes of remaining input before reading the continuation byte. These omissions allowed overlong, truncated, and structurally invalid sequences to be silently coerced into arbitrary Unicode scalar values.

Attack Vector

Exploitation is network-reachable and requires no authentication or user interaction. An attacker submits a payload containing crafted byte sequences to an API or service that forwards bytes into ujson.dumps(..., reject_bytes=False). The encoder produces a JSON document containing Unicode characters that differ from the original bytes. Systems that signed, logged, or validated the pre-encoding bytes may now disagree with consumers that parse the encoded output, enabling validation bypass and integrity drift.

c
// Patch excerpt: src/ujson/lib/ultrajsonenc.c
// Adds continuation-byte validation for 2-byte UTF-8 sequences
      case 2:
      {
        JSUTF32 in;
        JSUTF16 in16;

        if (end - io < 2)
        {
          enc->offset += (of - enc->offset);
          SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string");
          return FALSE;
        }
        if ((io[1] & 0xc0) != 0x80)
        {
          enc->offset += (of - enc->offset);
          SetError (obj, enc, "Invalid continuation byte in 2-byte UTF-8 sequence detected when encoding string");
          return FALSE;
        }

        memcpy(&in16, io, sizeof(JSUTF16));
        in = (JSUTF32) in16;

Source: GitHub commit 169eaf3

The decoder receives a parallel hardening for overlong 2-byte sequences in ultrajsondec.c, ensuring that decoded code points below 0x80 are rejected with an explicit error rather than emitted as valid characters.

Detection Methods for CVE-2026-54911

Indicators of Compromise

  • JSON outputs containing the Unicode replacement character (U+FFFD) or unexpected Latin-1 substitutions where binary input was supplied
  • Application logs showing successful encoding of payloads that fail downstream UTF-8 validators
  • Mismatch between request-body hashes and the hash of the re-serialized JSON stored or forwarded by the service

Detection Strategies

  • Inventory Python dependencies for ujson versions below 5.13.0 using pip list or SBOM tooling
  • Grep source repositories for calls to ujson.dumps, ujson.dump, or ujson.encode that pass reject_bytes=False
  • Add unit tests that submit known-malformed UTF-8 (truncated 2-byte sequences, lone continuation bytes) and assert the encoder raises rather than rewrites

Monitoring Recommendations

  • Alert on integrity failures between pre- and post-serialization payload hashes in API gateways
  • Monitor for spikes in JSON parse errors at downstream consumers, which can indicate upstream silent rewriting
  • Track package upgrade status for ujson across build pipelines and container images

How to Mitigate CVE-2026-54911

Immediate Actions Required

  • Upgrade UltraJSON to version 5.13.0 or later across all Python environments
  • Audit application code for reject_bytes=False usage and remove it where str input is acceptable
  • Validate UTF-8 input at the application boundary before passing bytes to any JSON encoder

Patch Information

The issue is fixed in UltraJSON 5.13.0. The patch adds explicit continuation-byte and length checks in both the encoder and decoder paths. Refer to the GitHub Security Advisory GHSA-3j69-69wj-xqx2 and the 5.13.0 release notes for full details.

Workarounds

  • Stop passing reject_bytes=False; allow ujson to reject bytes input by default and convert to str explicitly
  • Pre-validate byte payloads with bytes.decode('utf-8', errors='strict') before encoding to JSON
  • Switch temporarily to the standard library json module for paths that must accept untrusted bytes
bash
# Upgrade ujson to the patched release
pip install --upgrade 'ujson>=5.13.0'

# Verify installed version
python -c "import ujson; print(ujson.__version__)"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.