---
id: "CVE-2026-113667"
kind: "vulnerability"
aliases: ["CVE-2026-113667", "GHSA-44qr-rrjg-2cqq"]
title: "ApostropheCMS: CAPTCHA response token not URL-encoded"
severity: "medium"
cvss: 5.3
epss: 0.003530000103637576
exploited: false
status: "open"
category: "package"
products: [{"name": "@apostrophecms/form", "fixed": ["1.5.5"], "affected": "< 1.5.5", "ecosystem": "npm"}, {"name": "@apostrophecms/login-recaptcha", "fixed": ["1.2.1"], "affected": "< 1.2.1", "ecosystem": "npm"}, {"name": "@apostrophecms/login-hcaptcha", "fixed": ["1.3.0"], "affected": "< 1.3.0", "ecosystem": "npm"}]
ecosystems: ["npm"]
tags: ["apostrophecms", "cwe-116", "next.js", "node", "package", "self-hosted"]
not_affected_if: ["fixed-version-installed", "no-captcha-configured"]
published_at: "2026-10-20T18:05:35+00:00"
first_seen_at: "2026-10-23T19:11:32+00:00"
updated_at: "2026-10-23T21:57:21+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-44qr-rrjg-2cqq", "first_seen_at": "2026-10-23T19:11:32+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-113667", "first_seen_at": "2026-10-23T21:57:21+00:00"}]
---

# ApostropheCMS: CAPTCHA response token not URL-encoded

The ApostropheCMS form and login CAPTCHA modules put the user-supplied CAPTCHA token into the server-side verify request without URL-encoding it. A crafted token can inject extra query parameters into the reCAPTCHA or hCaptcha verification call, which can force verification failures and enable automated bypass probing.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- npm:@apostrophecms/form affected < 1.5.5 fixed 1.5.5
- npm:@apostrophecms/login-recaptcha affected < 1.2.1 fixed 1.2.1
- npm:@apostrophecms/login-hcaptcha affected < 1.3.0 fixed 1.3.0

## How to check

Check installed versions: npm ls @apostrophecms/form @apostrophecms/login-recaptcha @apostrophecms/login-hcaptcha
Flagged if @apostrophecms/form is below 1.5.5, login-recaptcha below 1.2.1, or login-hcaptcha below 1.3.0.

## Fix

Upgrade @apostrophecms/form to 1.5.5, @apostrophecms/login-recaptcha to 1.2.1, and @apostrophecms/login-hcaptcha to 1.3.0.
Source remediation suggests encoding the secret and response values or building the request with URL searchParams.

## Timeline

- 2026-10-23T19:11:32+00:00 ghsa https://github.com/advisories/GHSA-44qr-rrjg-2cqq
- 2026-10-23T21:57:21+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-113667

## From the sources

**Summary**
Form and login CAPTCHA verification interpolate the user-supplied widget token unencoded into the server-side verification URL/body, allowing a crafted token to inject query parameters into the reCAPTCHA/hCaptcha verify request.

**Details**
- `packages/form/lib/recaptcha.js:39` — `recaptchaUri = 'https://www.google.com/recaptcha/api/siteverify?secret=${recaptchaSecret}&response=${input.recaptcha}'`
- `packages/login-recaptcha/index.js:44` — same pattern for login
- `packages/login-hcaptcha/index.js:47` — `body: 'response=${token}&secret=${secret}'`

**PoC**
```
input.recaptcha = 'attacker_token&secret=INJECTED_SECRET&something=1'
→ resulting verify URL:
   https://www.google.com/recaptcha/api/siteverify?secret=<real>&response=attacker_token&secret=INJECTED_SECRET&something=1
# (replicated exactly from recaptcha.js:39)
```

**Impact**
Low: a crafted token smuggles extra `key=value` pairs (`secret`, extra `response`) into the outbound verify call, forcing verification failures (DoS of the captcha gate and of captcha-gated login/form flows) and enabling automated bypass probing; no secret exfiltration.

**Remediation** — Build the verify request with `URL` + `searchParams` (or `encodeURIComponent` on both `secret` and `response`), and validate the token against `^[A-Za-z0-9._-]{1,2048}$` before use.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
