☠️
EXFILTRATING
DATA...
01010111 10110010 00101001 11000110 01101100 10011011 00010001 11100101 01000010 10101111
[ <-- BACK_TO_SEARCH ]
[ VENDOR STATS ]
CVSS: 5.3 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N 🐛 CWE-304
👁️
Common Weakness Enumeration - Identifies the specific category of software weakness or flaw.

CVE-2026-100667

CVE-2026-100667 Vulnerability in Grav
📅 PUBLISHED: 2026-09-26 00:00 UTC 🔄 UPDATED: 2026-09-27 05:00 UTC
[ ZERO-DAY / UNPATCHED ] [ DEFENSE PATCH ↓ ]
💣 PoC: None
👁️
Proof of Concept - Indicates if functional exploit code is publicly available, drastically increasing the risk of immediate attacks.
🥷 MITRE: T1190
👁️
MITRE ATT&CK Tactic - Describes the strategy hackers use to execute this attack.
VULNERABLE: >= 3.8.7 and < 3.9.7 (grav-plugin-login)
CVSS VECTOR BREAKDOWN 5.3
AV: N Attack Vector Network
AC: L Attack Complexity Low
PR: N Privileges Required None
UI: N User Interaction None
S: U Scope Unchanged
C: L Confidentiality Low
I: N Integrity None
A: N Availability None
5.3
THREAT LEVEL
■ tracking this CVE ✓ independent patch confirmation ⧗ same-origin mirror (GHSA) ⚠ active exploitation verification policy →

Executive Summary

CVE-2026-100667 is an authentication-state confusion flaw (CWE-304) in the Grav CMS Login plugin (grav-plugin-login) affecting versions 3.8.7 through 3.9.6. When two-factor authentication (2FA) is enabled, the plugin's Login::isAuthenticated() method evaluated only the session flag confirming the password step had succeeded, rather than the flag confirming the full login had completed—so a session paused at the 2FA prompt was incorrectly treated as fully authenticated. An attacker who already knows a member's password but cannot satisfy that member's second factor can therefore read member-only content rendered by the authenticated() Twig function, the [authenticated] shortcode, and related conditional-rendering primitives. The flaw is limited to information disclosure (CVSS 5.3, C:L) and was corrected in grav-plugin-login 3.9.7.

⚡ AUTOMATE YOUR CVE INTELLIGENCE

This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.

›Patch confidence — UNVERIFIED to CONFIRMED, cross-referenced NVD + RHSA + Debian
›Exploit & PoC — poc_status, poc_url, has_exploit. Not in NVD.
›Shodan dorks — ready-made queries to find exposed vulnerable systems
›Detection rules — YARA · Wazuh · Elastic (all plans) · Sigma (Pro)
›pending_fields — know exactly which of 7 fields NVD hasn't processed yet
›Free backfill — data incomplete when you paid? Re-check within 30 days = 0 credits
PAYG €0.08/lookup Standard €19/mo (was €29) · 5k credits Pro €65/mo (was €99) · 20k credits FOUNDING PRICE · LOCKED FOR LIFE · ENDS 31 DEC 2026
[ FROM €19/MO ]
Free sandbox key available
No signup required

Technical Analysis

The vulnerability resides in the interaction between Grav's session-based authentication state machine and its content-gating primitives. Grav performs authentication in discrete steps: first the credential (password) check, then—if enabled—a second-factor challenge. These two states are tracked via separate session flags. Correct behavior requires that downstream authorization decisions consult the flag indicating the entire login sequence completed.

In the affected versions, Login::isAuthenticated() returned a truthy result as soon as the password-step flag was set. That method underpins several Twig/shortcode level gates:

  • the no-argument authenticated() Twig function,
  • the authenticated(null, 'group') form used for group-gated content,
  • the [authenticated] shortcode (and the inverse [guest] shortcode, which was consequently evaluated too early).

Because the 2FA completion flag was never consulted, any session that had merely passed the password challenge—i.e., was sitting at the "enter your 2FA code" prompt—was reported as authenticated. The bug is a classic authentication-state confusion (CWE-304, "Missing Critical Step in Authentication") in which a partial-credential state is conflated with a fully-authorized state.

Crucially, the flaw does not affect the permission-bearing form authenticated('some.permission'), which routes through UserObject::authorize() and therefore performs an independent authorization check. Access controlled by Grav's access: front-matter/page rule is also unaffected, because that path does not depend on the vulnerable isAuthenticated() shortcut. As a result, the defect is strictly a disclosure primitive: it can reveal gated content rendered by Twig conditionals, but it does not mint a fully-authenticated session, does not grant write capability, and does not allow the attacker to act as the compromised user.

Attack surface: any Grav site running grav-plugin-login in the affected range with 2FA enabled and using authenticated(), authenticated(null, 'group'), [authenticated], or [guest] to protect content. The flaw is remotely reachable (AV:N), requires no privileges on the target (PR:N), needs no user interaction (UI:N), and has low complexity (AC:L) — the attacker merely has to hold a valid password.

Exploitation Scenarios

No public PoC, template, or exploit code exists for this CVE; the chain below is inferred strictly from the NVD description and the vulnerability class (authentication-state confusion / missing critical step).

  1. Reconnaissance and target identification. The attacker identifies a Grav CMS instance running the Login plugin within the affected version window (3.8.7–3.9.6) and determines, via normal login-page behavior, that 2FA is enforced after the password step. This is a low-noise, pre-auth observation using only the standard login flow.

  2. Credential acquisition. The attacker must already possess a valid member password (phishing, credential stuffing, password reuse, prior breach data). This is a precondition, not a capability gained by the CVE.

  3. Triggering the flaw. The attacker authenticates with the known password. The application accepts the credential and advances the session to the second-factor prompt, at which point the session has the password-step flag set but the login-completion flag unset. The attacker does not supply a valid 2FA code.

  4. Bypassing content gating. Because Login::isAuthenticated() consults only the password-step flag in affected versions, a request for content gated by the no-argument authenticated() Twig function or the [authenticated] shortcode is rendered as if the user were fully logged in. The [guest] shortcode is correspondingly evaluated as "not a guest" (i.e., authenticated) too early. The attacker reads content that should be restricted to fully authenticated members.

  5. Post-exploitation impact. The impact is confined to disclosure of the specific member-only content rendered by the vulnerable primitives. The attacker does not obtain a completed session, cannot reach pages protected by an access: rule, cannot use the permission-scoped form authenticated('some.permission') (which goes through UserObject::authorize()), and cannot perform actions as the victim. There is no privilege escalation, no code execution, and no lateral movement enabled by this CVE.

Detection note: Exploitation leaves a distinctive fingerprint — credentialed login activity that advances to the 2FA stage followed by authenticated content requests without completion of the second factor. This originates from pre-auth (not yet privileged) traffic and requires log correlation across the login and content-serving layers.

Impact Assessment

The CVSS v3.1 base score is 5.3 (Medium), vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N.

  • Confidentiality: Low — only content gated by the specific authenticated()/[authenticated]/[guest] primitives is disclosed; permission-scoped and access:-protected resources remain protected.
  • Integrity: None — the attacker cannot modify data or state.
  • Availability: None — no denial-of-service component.
  • Scope: Unchanged — impact stays within the vulnerable component.

Business impact is generally limited but non-trivial for membership sites, subscription portals, internal documentation hubs, or communities that rely on authenticated()/[authenticated] to gate member-only material. Where such gating protects regulated, proprietary, or personally identifying content, even a "Low" confidentiality score can translate into compliance exposure (e.g., privacy or contractual data-handling obligations). Blast radius is bounded by (a) 2FA being enabled and (b) the site using the affected shortcodes/Twig conditionals for content gating rather than access: rules or the permission-scoped form. The precondition that the attacker must already know a member's password means this is most credibly exploited as an amplifier on top of an existing credential compromise—converting "password but not second factor" into "read member content." No CISA KEV listing and no public exploit evidence currently indicate active in-the-wild exploitation, and EPSS has not been scored by FIRST.org.

Detection Guidance

Sigma Rule

title: Grav Login Plugin 2FA Bypass - Authenticated Content Access Without 2FA Completion
id: 8f4c2a10-7b3e-4d21-9c15-grav100667
status: experimental
description: Detects requests for 2FA-gated Grav content where the session has passed only the password step and not the second-factor step (CVE-2026-100667).
references:
  - https://nvd.nist.gov/vuln/detail/CVE-2026-100667
author: valtersit.com Threat Intelligence
date: 2026-01-01
logsource:
  category: webserver
  product: grav
detection:
  selection_login:
    cs-uri-stem|contains:
      - '/user/login'
  selection_2fa:
    cs-uri-query|contains: '2fa'
  selection_gated_content:
    cs-uri-stem|startswith: '/'
  condition: selection_login or selection_2fa
falsepositives:
  - Legitimate users who complete the second factor within the same session.
  - Automated health checks against public landing pages.
level: medium
tags:
  - attack.t1190
  - cve.2026-100667

YARA Rule

rule CVE_2026_100667_Grav_Login_2FA_Bypass
{
    meta:
        description = "Detects grav-plugin-login sources in affected range with isAuthenticated() logic (CVE-2026-100667)"
        author = "valtersit.com Threat Intelligence"
        reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-100667"
        date = "2026-01-01"
        severity = "medium"

    strings:
        $login_class   = "class Login" ascii wide
        $auth_func     = "isAuthenticated" ascii wide
        $shortcode_auth = "[authenticated]" ascii wide
        $shortcode_guest = "[guest]" ascii wide
        $ver_377 = "3.8.7" ascii wide
        $ver_396 = "3.9.6" ascii wide

    condition:
        (
            $login_class and $auth_func
        ) and (
            $shortcode_auth or $shortcode_guest
        )
}

Suricata IDS Rule

alert http any any -> any any (msg:"CVE-2026-100667 Grav Login Plugin 2FA Bypass - Authenticated Content Fetch Without 2FA"; flow:established,to_server; http.method; content:"GET"; http.uri; content:"/user/login"; nocase; http.header; content:"Cookie"; nocase; http.cookie; content:"grav-site"; nocase; reference:cve,2026-100667; reference:url,nvd.nist.gov/vuln/detail/CVE-2026-100667; classtype:attempted-recon; sid:2026100667; rev:1;)

Elastic Detection

sequence by source.ip with maxspan=5m
  [ network where event.category == "network" and url.path : "/user/login" and http.request.method == "POST" ]
  [ network where event.category == "network" and http.request.method == "GET" and not url.path : "*/user/login*" and user.name == null ]

Splunk SPL Query

index=web sourcetype=access_combined
| eval is_login=if(match(uri, "/user/login.*"), 1, 0)
| eval is_2fa=if(match(uri, ".*2fa.*"), 1, 0)
| stats count values(uri) as uris by clientip, session_id
| where is_2fa=0 AND is_login=1
| table clientip, session_id, uris, count
| sort - count

Wazuh OSSEC Rule

<group name="web,grav,cve-2026-100667,">
  <rule id="100667" level="7">
    <decoded_as>web-accesslog</decoded_as>
    <field name="url">^/user/login</field>
    <description>CVE-2026-100667: Grav Login plugin 2FA bypass - client authenticated past password step while reaching 2FA-gated content</description>
    <mitre>
      <id>T1190</id>
    </mitre>
    <group>cve_2026_100667,</group>
  </rule>

  <rule id="100668" level="5">
    <if_sid>100667</if_sid>
    <field name="url">2fa</field>
    <description>CVE-2026-100667: Grav 2FA challenge endpoint reached - possible partial-auth session probing</description>
  </rule>
</group>

Mitigation & Patch Guidance

Patch confidence: 0/4 (UNPATCHED — no patch evidence from any tracked source). Although the NVD description states the issue is "Fixed in grav-plugin-login 3.9.7," no authoritative patch artifact, vendor advisory, changelog diff, or commit reference is currently tracked for this CVE. Treat all version claims as unverified until the vendor advisory and fixed release are independently confirmed. Do not rely on a version-number string alone as proof of remediation.

  1. Immediate mitigations

    • Prefer authenticated('some.permission') (which routes through UserObject::authorize()) or Grav's access: page/front-matter rules to gate sensitive content instead of the vulnerable no-argument authenticated() / authenticated(null, 'group') / [authenticated] primitives, which are the affected surfaces. This is unaffected per the description and is the most reliable stop-gap.
    • Replace [authenticated]/[guest] shortcode usage for sensitive content with permission-scoped or access:-rule gating wherever operationally possible.
    • Enforce strong, unique member credentials and reduce credential-reuse exposure, since exploitation requires a known password.
    • Monitor and rate-limit login attempts to disrupt credential stuffing that could supply the required precondition.
    • Review logs for credential-valid sessions that abandoned the 2FA prompt yet continued requesting gated content.
  2. Patch / upgrade steps

    • Monitor the grav-plugin-login project (GitHub releases and CHANGELOG) for the 3.9.7 release and any accompanying security advisory; verify the advisory explicitly enumerates this CVE.
    • When a validated 3.9.7 (or later) artifact is available, back up the site and database, stage-upgrade in a test environment, confirm authenticated()/[authenticated]/[guest] behavior is corrected, then upgrade production.
    • Re-verify the fix by testing that a session at the 2FA prompt can no longer read content gated by the affected primitives, while authenticated('some.permission') and access:-protected pages remain correctly enforced.
  3. Long-term hardening

    • Adopt a policy of gating all sensitive content via explicit permission/authorization checks rather than boolean authentication shortcuts.
    • Integrate dependency scanning for Grav plugins and track plugin advisories in your vulnerability management program.
    • Preserve detailed authentication logs (password-step and 2FA-step transitions) to support detection of partial-auth bypass attempts.
    • Periodically review content gating code for reliance on authentication-state booleans that may conflate partial and completed login states.

References

Threat actor / exploit-in-the-wild status: No known threat actor campaigns, no public PoC, no Nuclei template, and no exploit code are associated with CVE-2026-100667. CISA KEV listing: NO. EPSS: not yet scored by FIRST.org.

👁️ SHODAN DORKS (THREAT HUNTING)

What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.

product:"Grav"
title:"Grav"
◈ SOURCE Analysis & enrichment: valtersit.com/cve/CVE-2026-100667/ · CVE data: NVD/MITRE (public domain) · © 2026 ValtersIT Hub
>_ SYSTEM_CORE: INTEL_ACTIVE
90% TEAM-CURATED // 10% AUTOMATED INGESTION.
ALL PATCH REFERENCES AND VERSION DATA SOURCED FROM NVD + OSV OFFICIAL REGISTRIES.