Sep 22, 2026·5 min read·19 visits
A replay vulnerability in nginx-ignition allows attackers with primary credentials to reuse a valid, active 2FA TOTP code within its 30-second window to gain full administrative access.
nginx-ignition is a web-based user interface for managing the Nginx web server. In versions 2.33.0 through 2.35.0, the application is vulnerable to an improper authentication flaw (CWE-287) in its Multi-Factor Authentication (MFA) implementation. The stateless validation of Time-Based One-Time Passwords (TOTP) allows an attacker to reuse a captured, active verification code multiple times within the standard 30-second validity window, successfully bypassing secondary authentication checks if primary credentials are known.
The nginx-ignition application provides an administrative panel to configure reverse proxies, SSL certificates, and access rules for the Nginx web server. Securing this interface is critical because access to this panel translates to broad administrative authority over the underlying system. To secure administrative access, nginx-ignition supports Multi-Factor Authentication (MFA) using Time-Based One-Time Passwords (TOTP).
In versions 2.33.0 through 2.35.0, the verification logic does not enforce single-use restrictions on TOTP codes. If an attacker intercepts or obtains a valid TOTP token along with the victim's primary credentials, they can authenticate successfully using the exact same code, provided the transmission occurs within the 30-second validity window of the token.
This vulnerability is classified under CWE-287 (Improper Authentication). The lack of stateful tracking of verified tokens exposes the administrative console to unauthorized access via credential replay, weakening the security guarantees of the multi-factor authentication mechanism.
The root cause of this vulnerability lies in the stateless nature of the application's TOTP verification logic. Standard TOTP implementations (as defined in RFC 6238) generate passwords based on a shared secret and the current Unix time step, typically lasting 30 seconds. To prevent replay attacks, the verifying server must maintain a state of previously accepted tokens and reject any token that has already been validated during its current time step.
Prior to version 2.35.1, nginx-ignition validated TOTP codes purely through mathematical verification using the Go library github.com/pquerna/otp. The library checks if the input matches the mathematical state expected for the secret key during the active temporal window.
Because the application failed to record whether a code had already been used, any mathematically correct token remained valid for multiple authentication attempts until the 30-second interval elapsed. If an administrative user successfully authenticated, an attacker who intercepted the transmitted token could immediately replay it to establish their own authenticated session.
The remediation introduced stateful tracking to record and verify previously used codes. In the user data model located at core/user/model.go, the application now maintains an array of recently processed TOTP tokens:
type TOTP struct {
- Secret *string
- Validated bool
+ Secret *string
+ LastUsedCodes []string
+ Validated bool
}In core/user/service.go, the login flow was updated to block subsequent authentications with the same token. The application executes TryUpdateLastUsedTOTPCode via the database repository after mathematical validation passes. If the code has been used before, authentication is rejected:
if !totp.Validate(code, *totpData.Secret) {
return AuthenticationFailed, nil, nil
}
+
+ updated, err := s.repository.TryUpdateLastUsedTOTPCode(ctx, usr.ID, code)
+ if err != nil || !updated {
+ return AuthenticationFailed, nil, err
+ }
+
+ usr.TOTP.LastUsedCodes = append([]string{code}, usr.TOTP.LastUsedCodes...)
+ if len(usr.TOTP.LastUsedCodes) > 3 {
+ usr.TOTP.LastUsedCodes = usr.TOTP.LastUsedCodes[:3]
+ }To ensure thread safety and avoid race conditions, the validation relies on database-level checks. In database/user/repository.go, an atomic query ensures that duplicate codes are ignored by using explicit database updates:
+func (r *repository) TryUpdateLastUsedTOTPCode(ctx context.Context, id uuid.UUID, code string) (bool, error) {
+ result, err := r.database.Update().
+ Model((*userModel)(nil)).
+ Set("totp_last_used_codes = SUBSTR(? || COALESCE(',' || totp_last_used_codes, ''), 1, 20)", code).
+ Where("id = ? AND (totp_last_used_codes IS NULL OR (',' || totp_last_used_codes || ',') NOT LIKE ?)", id, "%,"+code+",%").
+ Exec(ctx)
...If the SQL query modifies zero rows due to the conditional checks in the Where statement, the repository returns false, causing the authentication workflow to abort.
To exploit this vulnerability, an attacker must first possess the victim's primary login credentials (username and password). Once credentials are acquired, the attack requires interception of the user's login sequence, which can occur on unencrypted networks or via administrative logging.
An attacker position on a local area network or a shared proxy allows sniffing of the unencrypted JSON payload directed to /api/users/login. The payload exposes the standard username, password, and active 6-digit TOTP string.
By programmatically executing an HTTP POST request containing the captured credentials and the identical TOTP string within the active 30-second time-step, the server's stateless logic authorizes the second request. The endpoint responds with a unique, valid administrative JSON Web Token (JWT) for the attacker's session, granting immediate access to the administrative dashboard.
Successful exploitation of this flaw completely neutralizes the security benefits of Multi-Factor Authentication. The vulnerability yields administrative privileges to the nginx-ignition dashboard, allowing adversaries to modify active Nginx server blocks, alter SSL parameters, write unauthorized redirection rules, and modify administrative user settings.
Although the CVSS v3.1 score is calculated as 4.2 (Medium), the real-world operational threat is elevated. The CVSS metric designates a high complexity (AC:H) because the exploit requires sniffing the network traffic or acquiring the token stream dynamically during user sign-on, alongside needing primary credentials (PR:H).
If an organization hosts nginx-ignition on unencrypted HTTP channels within corporate local networks, the risk increases exponentially. The vulnerability allows rapid escalation of access from basic credential theft to complete network configuration control.
The recommended remediation is upgrading the nginx-ignition deployment directly to version v2.35.1 or higher. The patch fully mitigates the reuse vector by transitioning token verification from a purely mathematical calculation to a stateful database constraint.
The implemented fix is complete for standard operational deployments. By tracking the three most recently validated codes, the database check safely covers the default 30-second time window as well as common clock drift adjustments. Because the database operation is atomic, race conditions are blocked, preventing multiple login endpoints from parallel processing the same token.
CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
nginx-ignition lucasdillmann | >= v2.33.0, <= v2.35.0 | v2.35.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-287 (Improper Authentication) |
| Attack Vector | Network |
| CVSS v3.1 Score | 4.2 (Medium) |
| Exploit Status | Proof-of-Concept / Methodology Validated |
| CISA KEV Status | Not Listed |
| Attack Complexity | High |
| Privileges Required | High |
The application performs authentication check on users, but does not sufficiently protect against authentication bypass methods such as replay attacks in multi-factor authentication systems.
CVE-2026-12411 is a broken access control vulnerability in the DevLXD interface of Canonical LXD versions 6.6 through 6.8. The flaw resides in the devLXDInstancePatchHandler component, which fails to verify storage volume ownership when an instance attaches a new disk device via the /dev/lxd guest socket. When the security.devlxd.management.volumes configuration option is enabled, an untrusted guest or DevLXD identity can issue a crafted HTTP PATCH request referencing another tenant's custom storage volume. The LXD host daemon subsequently mounts the target volume into the requesting guest, permitting unauthorized cross-tenant read and write operations.
CVE-2026-105769 (GHSA-5q7h-w9jf-cx97, GO-2026-6225) is an origin validation error and credential exfiltration vulnerability affecting Kaniko prior to version 1.25.20. The flaw stems from an unanchored regular expression in the integrated Azure Container Registry (ACR) credential helper (github.com/chrismellard/docker-credential-acr-env). When Kaniko processes a Dockerfile containing an image reference hosted on a lookalike domain containing an ACR suffix as a substring (e.g., x.azurecr.io.attacker.com), the credential helper acquires a Microsoft Entra ID access token for Azure Resource Manager and transmits it via HTTP POST to the attacker-controlled host.
CVE-2026-62300 is an uncontrolled resource consumption vulnerability (CWE-400) affecting the daemon mode of filecoin-pin in versions up to and including 1.1.0. The daemon implements the IPFS Pinning Service API to store content on Filecoin's Proof of Data Possession (PDP) service. Due to the absence of rate limits, concurrency caps, execution timeouts, and Directed Acyclic Graph (DAG) traversal limits, an authenticated user—or an unauthenticated user when authentication is disabled—can exhaust system resources via crafted POST /pins requests.
CVE-2026-61536 is a high-severity Remote Code Execution (RCE) vulnerability in the masci/banks Python library prior to version 2.4.3. The flaw exists within the CompletionExtension component, which parses JSON-serialized Tool definitions directly from rendered Jinja template bodies inside {% completion %} blocks. When handling tool calls returned by an LLM, the library dynamically resolves the target callable using importlib.import_module() and getattr() based on an unvalidated import_path string. An attacker who can supply or modify prompt templates can inject a malicious Tool JSON object pointing to arbitrary Python functions (such as os.system), bypassing the Jinja SandboxedEnvironment introduced in version 2.4.2 and achieving arbitrary code execution when the LLM invokes the tool.
Payload CMS contains a missing authorization vulnerability (CWE-862) in its client-side upload instructions endpoint and the `@payloadcms/storage-vercel-blob` storage adapter. Two distinct logic defects allow authenticated users lacking collection-level `create` or `update` permissions to generate signed upload tokens and upload arbitrary files directly to external cloud storage.
CVE-2026-55098 (GHSA-93cm-2v4m-c56c) is an authorization bypass and sensitive information disclosure vulnerability in Basekick-Labs Arc prior to version 26.06.2. The flaw stems from an incomplete remediation of CVE-2026-47735, which failed to restrict the full suite of DuckDB table-valued filesystem I/O functions and quoted-identifier invocations. Because Arc's query parser ignores function calls during table reference extraction, authenticated users with minimal or empty permissions can invoke functions like parquet_scan(), glob(), and read_blob() to read, enumerate, and extract telemetry data across all tenant databases residing within the shared local storage root.