Disclosure summary
The pure-PHP X25519 scalar multiplication in phpseclib is not constant-time. Field addition and subtraction each perform a **data-dependent conditional modular reduction**, so the cost of each Montgomery-ladder step is a linear function of that step's reduction count which is a quantity determined by the secret scalar's *prefix*. An observer with per-ladder-step resolution recovers the 251-bit clamped private scalar. This is a per-step leak, not an aggregate one: an instrumented code proof-of-concept recovers 20/20 test keys from 32 observed operations, and an observer that counts libgmp calls instead of timing them recovers a key from a **single** operation. This is **not** a low-order-input issue. Recovery works with the RFC 7748 base point `u = 9`, with no attacker-chosen input at all. Rejecting low-order public values does not close it. ## 2. Affected component Confirmed on **phpseclib 3.0.56** (338 files under `phpseclib/`,`sha256(sorted(relpath NUL file_sha256 LF)) = cc7250b611f520e809131aab0931503457c44d8cbfb10d535251c6fec5f62a2b`). The code appears unchanged across the 3.0 series wherever Curve25519 is supported, please confirm the affected range. | file:line | role | |---|
Source-specific records & product guidance
Sources retain their own attribution and scoring. Follow the original record to confirm affected versions, fixed releases, and configuration conditions.
GitHub Reviewed Security Advisories · GHSA-q97c-8qh3-fpc6
Open original source · Updated Sep 29, 2026
phpseclib — non-constant-time X25519 scalar multiplication permits full private-key recovery
Source severity: MEDIUM / 0
| Ecosystem | Package | Affected range | First patched |
|---|---|---|---|
| composer | phpseclib/phpseclib | < 3.0.57 | 3.0.57 |
| composer | phpseclib/phpseclib | >= 4.0.0, < 4.0.1 | 4.0.1 |
Original records & references
- NIST NVD record
- CVE Program record
- github.com — Reviewed advisory
PUBLISHED 2026-09-08T17:24:29-04:00
MODIFIED 2026-09-29T17:15:47-04:00
INGESTED 2026-10-06T11:43:08-04:00