Skip to content

VNX-1039: reCAPTCHA v3 verdict accepted without checking the score

Reports Python and JavaScript/TypeScript handlers in reCAPTCHA v3 projects that accept the siteverify response on success alone, and score checks against 0, so the bot detector never rejects a bot.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-1039
Severity Medium
SARIF level warning
Kind sast
Languages JavaScript / TypeScript, Python
CWE CWE-1039
CAPEC CAPEC-66
ATT&CK T1190
CWSS vector CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C
Tags captcha recaptcha bot-detection cwe-1039
Source internal/sast/rules/vnx-1039.rego

Overview

VNX-1039 maps to CWE-1039: Automated Recognition Mechanism with Inadequate Detection or Handling of Adversarial Input Perturbations. reCAPTCHA v3 is an automated recognition mechanism: siteverify answers success: true for every well-formed token, bots included, and the bot/human judgement is only in the score (0.0 to 1.0). The rule reports:

  • in a project that uses reCAPTCHA v3 (grecaptcha.execute(...), api.js?render=<site key>, react-google-recaptcha-v3, a RECAPTCHA_V3 name), a file that handles the siteverify response and reads success but never mentions the score;
  • a score compared against 0 (score > 0, score >= 0.0), which accepts every request.

Not reported: reCAPTCHA v2, hCaptcha and Turnstile projects (no score; success is the verdict), handlers that read the score, comments and test files. CWE-1039 in general (machine-learning classifiers that adversarial input can fool) has no static signature; this rule covers the concrete case of a bot-detection score being ignored.

Why This Matters

A v3 integration that checks only success blocks nothing: an automated client that obtains any token passes, so sign-up, login and contact forms are open to credential stuffing and spam while the team believes they are protected.

What Gets Flagged

result = r.json()
if not result["success"]:
    abort(403)
const { success } = await resp.json();
return data.get("success") and data.get("score", 0) >= 0.0

Remediation

  1. Reject requests whose score is below a threshold suited to the action (Google suggests starting at 0.5).
  2. Check that action matches the action the page executed, and that hostname is yours.

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-1039
// nosec vnx-1039

Or record an ignore rule: vulnetix ignore add --rule vnx-1039 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-1039.rego, cli/internal/sast/docs/vnx-1039.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.