CVE-2026-3214
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Drupal is an open-source content management system known for its flexibility, robust features, and strong community support. Organizations of all sizes use it to build and manage dynamic websites and web applications.
CAPTCHA is a Drupal module that protects forms from automated submissions by adding human-verification challenges such as image, math, or reCAPTCHA tests. It integrates with common Drupal forms and lets administrators choose which forms are protected and which challenge type to use.
Broken Access Control occurs when an application fails to properly enforce restrictions on what authenticated users are allowed to do, enabling attackers to access unauthorized functionality, data, or resources. It often stems from inadequate validation of user permissions, allowing someone to bypass intended security boundaries and perform actions beyond their assigned role.
Impact highly depends on which form is protected. On affected sites, this could enable spam, abusive submissions, workflow abuse, or other downstream effects specific to the form being protected.
Details
Module Info
- Product: Drupal 7
- Affected packages: CAPTCHA
- Affected versions: >=7.1.0 <=7.1.7
- Repository: https://git.drupalcode.org/project/captcha
- Published packages: https://www.drupal.org/project/captcha
- Package manager: composer
- Fixed in: CAPTCHA NES 7.1.8
Vulnerability Info
This medium-severity vulnerability is found in versions of the Drupal CAPTCHA module for Drupal 7 sites from 7.1.0 and 7.1.7 (inclusive).
CAPTCHA is supposed to be a one-time challenge: once a user solves it, that specific CAPTCHA session should no longer be reusable. However, due to a flaw in how the module handled the hidden CAPTCHA session ID and one-time token, the code could still accept a previously solved CAPTCHA session during later form processing instead of forcing a fresh challenge.
In practical terms, this means an attacker could solve one CAPTCHA legitimately, capture the associated hidden form values such as captcha_sid and captcha_token, and then reuse them in a later submission rather than solving a new CAPTCHA. That breaks the intended one-time protection and can let repeated automated or scripted submissions slip past the CAPTCHA after only a single successful solve.
Steps To Reproduce
Note that reproducing the issue is time-sensitive. It requires a race condition or, more formally, a timing window, in which an attacker submits a replay request during the brief interval between token invalidation and token regeneration.
Since it is difficult to reproduce manually, the steps use direct database manipulation to simulate the real-world race condition.
- Create a Drupal 7 installation and install a CAPTCHA module version that is vulnerable to the exploit, such as 7.1.7.
- Enable the CAPTCHA and Contact modules.
- Go to admin/config/people/captcha . Inside the Form Protection section:
- For the FORM ID, type "contact_site_form"
- Set the challenge type to Math
- Click Save Configuration.
- Go to admin/people/permissions:
- Set "Use the site-wide contact form" for the Anonymous role
- Click Save permissions.
Phase 1: Harvest a Solved Session
- In an incognito window, visit /contact and fill out the form (including the CAPTCHA).
- Before submitting the form, inspect the page source or DOM and record the value of the hidden captcha_sid field:
- View the source and find <input type="hidden" name="captcha_sid" value="[SOME_ID]">.
- Record the value for [SOME_ID].
- Solve the CAPTCHA normally and submit the contact form successfully. This is the step that creates a solved CAPTCHA session for the recorded captcha_sid.
Phase 2: Perform the Bypass
- This approach uses database access to simulate the vulnerable NULL-token state for the solved CAPTCHA session.
- In a terminal, set the token for the solved session to NULL:
ddev mysql -e "UPDATE captcha_sessions SET token = NULL WHERE csid = [SID]"- Open a second incognito window so you are using a different anonymous session.
- Visit /contact.
- Use browser developer tools to inspect the form before submitting it.
- Find the hidden captcha_sid field and replace its value with the solved session ID from Phase 1.
- Find the hidden captcha_token field and clear its value, or remove the field entirely.
- Fill out the rest of the contact form and submit it without solving the new CAPTCHA challenge.
Expected Result (Vulnerable code)
The form submits successfully without requiring a new CAPTCHA solve.
- Token Bypass: When captcha_token is missing or empty, the module sets the variable $posted_captcha_token to NULL. Since the session was already solved once, the database also contains NULL for the token. In PHP, NULL !== NULL is FALSE, so the validation check is skipped.
- Persistence Bypass: The module checks the status of the provided csid. Since you solved it in Phase 1, its status is CAPTCHA_STATUS_SOLVED (1). The module sees this and decides that "no CAPTCHA is required for this user."
- Ownership Bypass: The module fails to verify if the csid actually belongs to the user currently submitting the form, allowing cross-session reuse.
Verification of Fix
After applying the patches provided earlier, repeat the "Perform the Bypass" phase. The submission should now fail with an error message: "CAPTCHA session reuse attack detected."
Addressing the Issue
Users of this module should apply one of the following mitigations:
- If the risk is unacceptable, disable CAPTCHA protection on affected workflows until the fix can be deployed
- Restrict access to protected forms to trusted or authenticated users where possible.
- Add secondary abuse controls such as rate limiting, moderation, or additional server-side validation on sensitive forms.
- Sign up for post-EOL security support—HeroDevs customers get immediate access to a patched version of this module.
Credits
- Andrew Belcher (andrewbelcher)
- Chris Dudley (dudleyc)
- Tamás Demeter-Haludka (tamasd)
- Tim Wood (timwood)