Vulnerability DatabaseGHSA-4v5c-4hwq-6f6m

GHSA-4v5c-4hwq-6f6m: 
PHP vulnerability analysis and mitigation

Summary

TOTP::expiresIn() computes period - ((now - epoch) % period) without checking that the clock has reached the epoch (src/TOTP.php:99-104). Both epoch and period can come from a provisioning URI. When the epoch is later than the current time, PHP's % returns a negative remainder, so the result is larger than the period. When the period is at or near PHP_INT_MAX (including any value the (int) cast saturates to it, such as 1e30), the sum overflows to a float, and the int return type raises a TypeError.

Impact

Factory::loadFromProvisioningUri() accepts such a URI, for example otpauth://totp/Alice?secret=JBSWY3DPEHPK3PXP&epoch=9223372036854775807&period=9223372036854775807. Calling expiresIn() on the returned object throws a TypeError. That class extends Error, not Exception, and does not implement OTPExceptionInterface, so the handling recommended in doc/Exceptions.md does not catch it. The request ends with an unhandled error, every time the stored URI is used. With the default period, the same kind of URI only produces a wrong countdown: up to 2 * period - 1 seconds, for example 46 seconds for a 30-second period. Only the party that supplies the URI is affected, and only if the application calls expiresIn() before now() or verify(), or separately from them. For the same object, those two methods already throw the documented InvalidParameterException. No code is accepted and nothing is disclosed.

Affected component

Line numbers are those of 11.4.3 and 11.5.0.

  • src/TOTP.php:99-104: TOTP::expiresIn() The epoch subtraction was introduced in 11.4.0 (commit 1236f0e, "Fix totp expires in (#237)"). Earlier versions ignored the epoch in expiresIn() and are not affected.

Proof of concept

use OTPHP\Factory;
use OTPHP\InternalClock;
$totp = Factory::loadFromProvisioningUri(
    'otpauth://totp/Alice?secret=JBSWY3DPEHPK3PXP&epoch=9223372036854775807&period=9223372036854775807',
    new InternalClock()
);
$totp->expiresIn(); // TypeError: OTPHP\TOTP::expiresIn(): Return value must be of type int, float returned

Remediation

Fixed in 11.4.4 and 11.5.1. If the current time is before the epoch, expiresIn() now throws InvalidParameterException ("The timestamp must be greater than or equal to the epoch."), as now() already does. From the epoch on, the result is always between 1 and the period, and the computation cannot overflow.

Workarounds

Call now() or verify() before expiresIn() and handle OTPExceptionInterface, or reject provisioning URIs whose epoch is in the future before you store them.

Credits

Reported by Anthropic's OSS Scanner (finding ANT-2026-LXJKQ7KL).


Source: NVD

Related PHP vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

CVE-2026-122053MEDIUM6.9
  • PHP logoPHP
  • symfony/serializer
NoYesNov 06, 2026
GHSA-526c-px8p-72x8MEDIUM4.3
  • PHP logoPHP
  • spomky-labs/otphp
NoYesNov 07, 2026
CVE-2026-123824LOW2.3
  • PHP logoPHP
  • symfony/config
NoYesNov 06, 2026
GHSA-h38w-h2gf-6qv2LOWN/A
  • PHP logoPHP
  • spomky-labs/otphp
NoYesNov 07, 2026
GHSA-4v5c-4hwq-6f6mMEDIUMN/A
  • PHP logoPHP
  • spomky-labs/otphp
NoYesNov 07, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Additional Wiz resources

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management