BREW-PARSEDMARC-CVE-2026… (GHSA-MM57-4V3P-RCHX)

Vulnerability from osv_homebrew – Published: 2026-10-31 11:02 – Updated: 2026-10-31 20:10 – Source website
VLAI
Summary
pyasn1 has quadratic-complexity denial of service in binary REAL decoding
Details

Summary

In pyasn1 0.6.4 and earlier, decoding a binary-encoded ASN.1 REAL with a large mantissa can consume CPU time quadratic in the mantissa length. The BER, CER, and DER decoders all use the affected RealPayloadDecoder. An application is exposed when it passes attacker-controlled ASN.1 containing a REAL value to one of these decoders, either without an asn1Spec or with a schema that includes REAL. The work occurs inside decode(); the application does not need to convert, print, or otherwise use the resulting REAL object.

This is distinct from CVE-2026-59886, which concerns converting an already-decoded REAL to a Python float. That issue was fixed in 0.6.4 and its advisory states that decoding alone does not trigger it.

Root cause and affected components

For binary REAL values, RealPayloadDecoder.valueDecoder in v0.6.4 builds the mantissa one octet at a time:

p = 0
while chunk:
    p <<= 8
    p |= chunk[0]
    chunk = chunk[1:]

Each shift processes an integer that grows with the mantissa; with byte strings, each slice also copies the remaining suffix. Repeating both operations for every octet makes decoding quadratic in mantissa size. The decoder's eight-octet length-field limit does not impose a practical mantissa-size limit for the inputs demonstrated below. CER and DER reuse the BER REAL payload decoder, so all three paths reach this loop.

The vulnerable loop is present in every available repository release tag inspected, from v0.2.1 through v0.6.4. Runtime measurements below were made on v0.6.4; older releases were checked for the loop, not benchmarked individually.

Impact

A comparatively small REAL value can hold a decoder worker on one CPU core for seconds or longer. The attacker must be able to supply data that the application sends to an affected decoder, and application-level input limits may reduce exposure. The demonstrated effect is CPU exhaustion during decoding; this advisory does not assert a network endpoint, unauthenticated access, or an affected downstream application by itself.

Reproduction and evidence

The following example uses pyasn1 0.6.4. The 0x09 tag identifies REAL; 0x80 0x00 selects a positive, base-2 binary value with a one-octet zero exponent, followed by a large mantissa. It exercises decode() only.

import time

from pyasn1.codec.ber import decoder as ber
from pyasn1.codec.cer import decoder as cer
from pyasn1.codec.der import decoder as der


def real_value(mantissa_octets):
    content = b"\x80\x00" + b"\xff" * mantissa_octets
    length = len(content).to_bytes(3, "big")
    return b"\x09\x83" + length + content


for codec in (ber, cer, der):
    for size in (50_000, 100_000, 200_000):
        substrate = real_value(size)
        started = time.process_time()
        value, rest = codec.decode(substrate)
        print(codec.__name__, size, time.process_time() - started)
        assert not rest
        assert tuple(value)[1:] == (2, 0)

The original report measured the following BER CPU times on repository commit aa05757. That commit is later than the official v0.6.4 tag; the vulnerable loop is identical in the tagged release.

Mantissa size Reporter's BER CPU time
50,000 octets 0.328 s
100,000 octets 1.299 s
200,000 octets 6.043 s
400,000 octets 24.095 s

The same report measured 5.645 s for a 200,000-octet mantissa through DER.

A separate local reproduction on the official v0.6.4 tag (d43496f, CPython 3.14.8, macOS arm64) measured BER at 0.209 s, 0.884 s, and 3.451 s for 50,000, 100,000, and 200,000 mantissa octets respectively. CER and DER each took about 0.89 s at 100,000 octets. These are machine-specific measurements; the repeated near-fourfold cost for doubled input is the relevant result. Neither reproduction calls float(), str(), or prettyPrint().

Fix

pyasn1 0.6.5 replaces the per-octet shift and slice loop with one int.from_bytes(bytes(chunk), "big") conversion. Sign, scale, exponent, and the decoded REAL tuple are preserved. The fix is in the shared BER payload decoder and therefore covers BER, CER, and DER. A local check of the 0.6.5 candidate decoded a 200,000-octet mantissa correctly through all three codecs; the check does not establish behavior for every application using REAL.

Workarounds

Upgrade to pyasn1 0.6.5. Until then, reject or strictly limit attacker-controlled ASN.1 input that may contain REAL values before passing it to pyasn1. The appropriate size limit depends on the application's available CPU time and request volume.


{
  "affected": [
    {
      "ecosystem_specific": {
        "fix": "bump",
        "range_state": "fixed",
        "resource": "pyasn1",
        "resource_purl": "pkg:pypi/pyasn1@0.6.5",
        "upstream_fixed_in": "0.6.5"
      },
      "package": {
        "ecosystem": "Homebrew",
        "name": "parsedmarc",
        "purl": "pkg:brew/parsedmarc"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "8.11.0"
            },
            {
              "fixed": "11.1.0_1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "database_specific": {
    "confidence": "high",
    "source": "matched",
    "strategy": "registry",
    "upstream_evidence": [
      {
        "ecosystem": "PyPI",
        "key": "pkg:pypi/pyasn1@0.6.5",
        "name": "pyasn1",
        "resource": "pyasn1",
        "strategy": "registry",
        "subject_version": "0.6.5"
      }
    ]
  },
  "details": "## Summary\n\nIn pyasn1 0.6.4 and earlier, decoding a binary-encoded ASN.1 REAL with a large mantissa can consume CPU time quadratic in the mantissa length. The BER, CER, and DER decoders all use the affected `RealPayloadDecoder`. An application is exposed when it passes attacker-controlled ASN.1 containing a REAL value to one of these decoders, either without an `asn1Spec` or with a schema that includes REAL. The work occurs inside `decode()`; the application does not need to convert, print, or otherwise use the resulting REAL object.\n\nThis is distinct from [CVE-2026-59886](https://github.com/advisories/GHSA-hm4w-wwcw-mr6r), which concerns converting an already-decoded REAL to a Python float. That issue was fixed in 0.6.4 and its advisory states that decoding alone does not trigger it.\n\n## Root cause and affected components\n\nFor binary REAL values, [`RealPayloadDecoder.valueDecoder` in v0.6.4](https://github.com/pyasn1/pyasn1/blob/v0.6.4/pyasn1/codec/ber/decoder.py#L535-L603) builds the mantissa one octet at a time:\n\n```python\np = 0\nwhile chunk:\n    p \u003c\u003c= 8\n    p |= chunk[0]\n    chunk = chunk[1:]\n```\n\nEach shift processes an integer that grows with the mantissa; with byte strings, each slice also copies the remaining suffix. Repeating both operations for every octet makes decoding quadratic in mantissa size. The decoder\u0027s [eight-octet length-field limit](https://github.com/pyasn1/pyasn1/blob/v0.6.4/pyasn1/codec/ber/decoder.py#L1704-L1717) does not impose a practical mantissa-size limit for the inputs demonstrated below. [CER](https://github.com/pyasn1/pyasn1/blob/v0.6.4/pyasn1/codec/cer/decoder.py#L51-L62) and [DER](https://github.com/pyasn1/pyasn1/blob/v0.6.4/pyasn1/codec/der/decoder.py#L23-L31) reuse the BER REAL payload decoder, so all three paths reach this loop.\n\nThe vulnerable loop is present in every available repository release tag inspected, from v0.2.1 through v0.6.4. Runtime measurements below were made on v0.6.4; older releases were checked for the loop, not benchmarked individually.\n\n## Impact\n\nA comparatively small REAL value can hold a decoder worker on one CPU core for seconds or longer. The attacker must be able to supply data that the application sends to an affected decoder, and application-level input limits may reduce exposure. The demonstrated effect is CPU exhaustion during decoding; this advisory does not assert a network endpoint, unauthenticated access, or an affected downstream application by itself.\n\n## Reproduction and evidence\n\nThe following example uses pyasn1 0.6.4. The `0x09` tag identifies REAL; `0x80 0x00` selects a positive, base-2 binary value with a one-octet zero exponent, followed by a large mantissa. It exercises `decode()` only.\n\n```python\nimport time\n\nfrom pyasn1.codec.ber import decoder as ber\nfrom pyasn1.codec.cer import decoder as cer\nfrom pyasn1.codec.der import decoder as der\n\n\ndef real_value(mantissa_octets):\n    content = b\"\\x80\\x00\" + b\"\\xff\" * mantissa_octets\n    length = len(content).to_bytes(3, \"big\")\n    return b\"\\x09\\x83\" + length + content\n\n\nfor codec in (ber, cer, der):\n    for size in (50_000, 100_000, 200_000):\n        substrate = real_value(size)\n        started = time.process_time()\n        value, rest = codec.decode(substrate)\n        print(codec.__name__, size, time.process_time() - started)\n        assert not rest\n        assert tuple(value)[1:] == (2, 0)\n```\n\nThe original report measured the following BER CPU times on repository commit `aa05757`. That commit is later than the official v0.6.4 tag; the vulnerable loop is identical in the tagged release.\n\n| Mantissa size | Reporter\u0027s BER CPU time |\n| ---: | ---: |\n| 50,000 octets | 0.328 s |\n| 100,000 octets | 1.299 s |\n| 200,000 octets | 6.043 s |\n| 400,000 octets | 24.095 s |\n\nThe same report measured 5.645 s for a 200,000-octet mantissa through DER.\n\nA separate local reproduction on the official v0.6.4 tag (`d43496f`, CPython 3.14.8, macOS arm64) measured BER at 0.209 s, 0.884 s, and 3.451 s for 50,000, 100,000, and 200,000 mantissa octets respectively. CER and DER each took about 0.89 s at 100,000 octets. These are machine-specific measurements; the repeated near-fourfold cost for doubled input is the relevant result. Neither reproduction calls `float()`, `str()`, or `prettyPrint()`.\n\n## Fix\n\npyasn1 0.6.5 replaces the per-octet shift and slice loop with one `int.from_bytes(bytes(chunk), \"big\")` conversion. Sign, scale, exponent, and the decoded REAL tuple are preserved. The fix is in the shared BER payload decoder and therefore covers BER, CER, and DER. A local check of the 0.6.5 candidate decoded a 200,000-octet mantissa correctly through all three codecs; the check does not establish behavior for every application using REAL.\n\n## Workarounds\n\nUpgrade to pyasn1 0.6.5. Until then, reject or strictly limit attacker-controlled ASN.1 input that may contain REAL values before passing it to pyasn1. The appropriate size limit depends on the application\u0027s available CPU time and request volume.",
  "id": "BREW-parsedmarc-CVE-2026-119197",
  "modified": "2026-10-31T20:10:04Z",
  "published": "2026-10-31T11:02:18Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/pyasn1/pyasn1/security/advisories/GHSA-mm57-4v3p-rchx"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-119197"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pyasn1/pyasn1/pull/132"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pyasn1/pyasn1/commit/ce3ec3390784780a530047e0e77be5ff457636a4"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/pyasn1/pyasn1"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pyasn1/pyasn1/releases/tag/v0.6.5"
    }
  ],
  "schema_version": "1.7.3",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "pyasn1 has quadratic-complexity denial of service in binary REAL decoding",
  "upstream": [
    "GHSA-mm57-4v3p-rchx",
    "CVE-2026-119197"
  ]
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
Events included in the timeline

Loading timeline…


    Loading…

    Loading…

    Loading…

    Related by attack behaviour

    Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.