CVE-2026-100667 Overview
CVE-2026-100667 is a two-factor authentication (2FA) bypass in the Grav CMS Login plugin (grav-plugin-login) affecting versions >= 3.8.7 and < 3.9.7. The flaw lets a session that has only completed the password step be treated as fully authenticated by the authenticated() Twig function and the [authenticated] shortcode. An attacker who knows a member's password but cannot satisfy the second factor can view member-only content gated by those primitives. The issue is tracked under [CWE-304: Missing Critical Step in Authentication].
Critical Impact
Attackers in possession of a valid password can read 2FA-protected content rendered by authenticated() or [authenticated], but cannot obtain a completed session, access access:-protected pages, or act as the user.
Affected Products
- grav-plugin-login version 3.8.7 and later
- grav-plugin-login versions prior to 3.9.7
- Grav CMS sites with 2FA enabled that rely on authenticated() Twig calls or [authenticated] / [guest] shortcodes
Discovery Timeline
- 2026-09-26 - CVE-2026-100667 published to NVD
- 2026-09-28 - Last updated in NVD database
Technical Details for CVE-2026-100667
Vulnerability Analysis
The Grav Login plugin exposes an authenticated() Twig helper and an [authenticated] shortcode so content authors can gate blocks of a page behind a logged-in session. Internally these primitives call Login::isAuthenticated(). On sites with 2FA enabled, that method consulted only the session flag indicating the password step had succeeded. It did not consult the separate flag indicating the full login flow had completed.
As a result, a session that is parked at the 2FA code prompt is treated as fully authenticated by those primitives. The inverse [guest] shortcode evaluates to false too early for the same reason. Impact is bounded: the attacker never obtains a completed session, cannot reach pages governed by an access: rule, and cannot perform actions as the user. The authenticated('some.permission') form, which flows through UserObject::authorize(), performs a proper permission check and is not affected.
Root Cause
The root cause is a missing authentication step check in Login::isAuthenticated(). The method validates only the first-factor (password) session state and omits the 2FA completion state before returning true. This maps to [CWE-304] where a critical step in the authentication process is skipped.
Attack Vector
Exploitation requires network access to the Grav site and prior knowledge of a victim member's password. The attacker submits valid credentials, reaches the 2FA code prompt, and then requests any page that renders member-only content through authenticated() or [authenticated]. The server renders the gated content without ever confirming the second factor. No code execution or lateral movement is possible through this flaw.
Verified exploitation code is not available. Refer to the GitHub Security Advisory GHSA-636m-8598-45r9 and the VulnCheck Advisory on Grav Plugin Bypass for technical details.
Detect Identity Attacks the Moment Authentication Fails
Singularity™ Identity surfaces credential misuse, lateral movement, and privilege escalation in real time, so you can contain the breach before it spreads.
Stop Identity AttacksDetection Methods for CVE-2026-100667
Indicators of Compromise
- Successful password submissions to /task:login followed by requests to member-gated pages without any twofa task submission in the same session.
- Repeated sessions that reach the 2FA prompt but never submit a valid 2FA code, yet still issue requests for pages containing authenticated() or [authenticated] content.
- Login plugin versions in the range 3.8.7 through 3.9.6 present in user/plugins/login/CHANGELOG.md or blueprints.yaml.
Detection Strategies
- Inventory Grav installations and flag any Login plugin version >= 3.8.7 and < 3.9.7.
- Review Grav access logs for sessions that render pages containing authenticated() Twig output without a preceding successful twofa task.
- Correlate web server logs for the same session ID issuing a password login and then multiple content requests with no 2FA completion event.
Monitoring Recommendations
- Enable verbose logging in the Login plugin to capture both password-step success and 2FA-completion events as distinct log entries.
- Alert on anomalous access patterns to pages known to host [authenticated] shortcodes by sessions that have not reached full login state.
- Monitor for unexpected downloads or views of member-only pages after off-hours password submissions.
How to Mitigate CVE-2026-100667
Immediate Actions Required
- Upgrade grav-plugin-login to version 3.9.7 or later on all Grav CMS instances.
- Audit pages that rely on authenticated() or [authenticated] for sensitive content and treat any such content as potentially exposed since the plugin was upgraded to 3.8.7.
- Force-rotate any member credentials known or suspected to be compromised, since this bypass only matters when a password is already known to an attacker.
Patch Information
The issue is fixed in grav-plugin-login3.9.7. The patched Login::isAuthenticated() now verifies the login-completion session flag in addition to the password-step flag, so authenticated() and [authenticated] only evaluate to true after the 2FA step has succeeded. See the GitHub Security Advisory GHSA-636m-8598-45r9 for the upstream fix details.
Workarounds
- Replace no-argument authenticated() calls and [authenticated] shortcodes with the permission-checking form authenticated('some.permission'), which routes through UserObject::authorize() and is not affected.
- Move sensitive content behind page-level access: rules in the page frontmatter, which continue to enforce full authentication including 2FA.
- Temporarily disable 2FA-gated member content pages until the plugin can be upgraded to 3.9.7.
# Upgrade the Login plugin via the Grav CLI
bin/gpm update login
# Verify the installed version is 3.9.7 or later
bin/gpm info login | grep -i version
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

