CVE-2026-94112 Overview
CVE-2026-94112 is an authentication weakness in mayswind ezBookkeeping versions before 2.0.0. The application fails to invalidate Time-based One-Time Password (TOTP) passcodes after use. Attackers who capture a valid passcode can replay it within the acceptance window, roughly 90 seconds, against multiple authorization attempts without detection.
The flaw is categorized under CWE-294: Authentication Bypass by Capture-replay. Exploitation requires attacker possession of valid primary credentials and the ability to intercept a fresh TOTP code, for example through phishing or a man-in-the-middle position.
Critical Impact
An attacker with stolen credentials and a captured TOTP passcode can bypass second-factor protections and reuse the same code across multiple authorization actions for approximately 90 seconds.
Affected Products
- mayswind ezBookkeeping versions before 2.0.0
- Self-hosted deployments of ezBookkeeping using the built-in two-factor authentication feature
- Docker and binary distributions of ezBookkeeping prior to the v2.0.0 release
Discovery Timeline
- 2026-09-20 - CVE-2026-94112 published to the National Vulnerability Database
- 2026-09-24 - Last updated in NVD database
Technical Details for CVE-2026-94112
Vulnerability Analysis
ezBookkeeping is an open-source personal finance and accounting web application written in Go. Prior to v2.0.0, the authorization endpoint in pkg/api/authorizations.go verified a submitted TOTP passcode against the user's shared secret but did not track whether the passcode had already been consumed.
TOTP codes are valid for a 30-second window. Most implementations accept the current step and one adjacent step to tolerate clock skew, yielding an effective acceptance window near 90 seconds. Without single-use enforcement, any code observed during that window remains valid for repeated submission.
An attacker who obtains valid primary credentials and intercepts one TOTP submission, through phishing, a compromised reverse proxy, or malicious browser extension, can replay the captured code to complete additional authorization actions. The behavior undermines the second-factor guarantee that possession of the authenticator device is required per transaction.
Root Cause
The verification path invoked the github.com/pquerna/otp/totp library to validate the passcode but did not record consumed codes. No duplicate-check state existed for two-factor passcodes, so the same six-digit value could be submitted repeatedly until the OTP step rotated.
Attack Vector
Exploitation is network-based but requires attacker interaction with both the victim and the ezBookkeeping endpoint. The attacker needs the victim's username and password plus a captured live TOTP passcode. Once obtained, the attacker submits the passcode to the authorization endpoint and can reissue it against additional authorization attempts within the acceptance window.
// Patch: pkg/api/authorizations.go — add time import used by duplicate-check logic
import (
"encoding/json"
"errors"
+ "time"
"github.com/pquerna/otp/totp"
// Patch: pkg/duplicatechecker/duplicate_checker_type.go — new checker type for 2FA passcodes
DUPLICATE_CHECKER_TYPE_IMPORT_TRANSACTIONS DuplicateCheckerType = 7
DUPLICATE_CHECKER_TYPE_OAUTH2_REDIRECT DuplicateCheckerType = 8
DUPLICATE_CHECKER_TYPE_NEW_CUSTOM_ICON DuplicateCheckerType = 9
+ DUPLICATE_CHECKER_TYPE_2FA_PASSCODE DuplicateCheckerType = 10
DUPLICATE_CHECKER_TYPE_FAILURE_CHECK DuplicateCheckerType = 255
)
Source: GitHub commit 3dd6286. The fix introduces a dedicated duplicate-checker entry for two-factor passcodes so that a submitted code is recorded and rejected on subsequent attempts.
Detection Methods for CVE-2026-94112
Indicators of Compromise
- Multiple successful authorization events for the same user within a 90-second window originating from different session tokens or IP addresses.
- Repeated submission of an identical six-digit TOTP value against the ezBookkeeping authorization endpoint.
- Authentication activity from geographic locations or user agents that do not match the account's historical baseline.
Detection Strategies
- Parse ezBookkeeping application logs for consecutive authorization requests referencing the same user identifier and inspect for reused OTP submissions.
- Correlate reverse-proxy or web application firewall (WAF) logs to flag rapid re-authorization from divergent source IPs during a single OTP step.
- Compare successful multi-factor authentication (MFA) completions against the count of distinct passcodes issued to detect replay patterns.
Monitoring Recommendations
- Forward ezBookkeeping and upstream reverse-proxy logs to a centralized logging platform and alert on more than one MFA success per user per 90-second interval.
- Enable alerts for authentication anomalies such as impossible-travel events or new-device logins immediately following an MFA challenge.
- Track failure-to-success ratios on the /api/v*/2fa/authorize path and investigate accounts with sudden spikes.
How to Mitigate CVE-2026-94112
Immediate Actions Required
- Upgrade all ezBookkeeping deployments to v2.0.0 or later, which enforces single-use TOTP passcodes.
- Rotate credentials for any account suspected of exposure, particularly where phishing or session interception is plausible.
- Restrict administrative access to the ezBookkeeping instance behind a VPN or IP allowlist until patching is complete.
Patch Information
The fix is delivered in the ezBookkeeping v2.0.0 release and implemented by commit 3dd6286. Additional context is available in the GitHub Security Advisory GHSA-p6qr-48g6-97q3 and the VulnCheck advisory for the TOTP replay attack.
Workarounds
- Place ezBookkeeping behind a reverse proxy that enforces short-lived, single-use authentication tokens or additional MFA layers.
- Terminate active sessions frequently and require re-authentication for sensitive operations to shrink the exploitable window.
- Enforce TLS everywhere and disable weak cipher suites to reduce the likelihood of passcode interception via network attackers.
# Upgrade a Docker-based ezBookkeeping deployment to the patched release
docker pull mayswind/ezbookkeeping:2.0.0
docker stop ezbookkeeping && docker rm ezbookkeeping
docker run -d --name ezbookkeeping \
-p 8080:8080 \
-v /path/to/data:/ezbookkeeping/data \
mayswind/ezbookkeeping:2.0.0
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.
