{"record":{"id":"6998f233e9d6e471","repo":"apereo/cas","slug":"recaptcha-score-received-is-less-than-the-threshol","errorCode":null,"errorMessage":"Recaptcha score received is less than the threshold score defined for CAS","messagePattern":"Recaptcha score received is less than the threshold score defined for CAS","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-captcha-core/src/main/java/org/apereo/cas/web/BaseCaptchaValidator.java","lineNumber":86,"sourceCode":"        val exec = HttpExecutionRequest.builder()\n            .method(HttpMethod.POST)\n            .url(recaptchaProperties.getVerifyUrl())\n            .headers(headers)\n            .entity(\"secret=%s&response=%s\".formatted(recaptchaProperties.getSecret(), recaptchaResponse))\n            .build();\n        return HttpUtils.execute(exec);\n    }\n\n    protected boolean parseCaptchaResponse(final HttpResponse response) throws Exception {\n        try (val content = ((HttpEntityContainer) response).getEntity().getContent()) {\n            val result = IOUtils.toString(content, StandardCharsets.UTF_8);\n            if (StringUtils.isBlank(result)) {\n                throw new IllegalArgumentException(\"Unable to parse empty entity response from \" + recaptchaProperties.getVerifyUrl());\n            }\n            LOGGER.debug(\"Recaptcha verification response received: [{}]\", result);\n            val node = MAPPER.reader().readTree(result);\n            if (node.has(\"score\") && node.get(\"score\").doubleValue() <= recaptchaProperties.getScore()) {\n                LOGGER.warn(\"Recaptcha score received is less than the threshold score defined for CAS\");\n                return false;\n            }\n            if (node.has(\"success\") && node.get(\"success\").booleanValue()) {\n                LOGGER.trace(\"Recaptcha has successfully verified the request\");\n                return true;\n            }\n        }\n        return false;\n    }\n}\n","sourceCodeStart":68,"sourceCodeEnd":97,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-captcha-core/src/main/java/org/apereo/cas/web/BaseCaptchaValidator.java#L68-L97","documentation":"BaseCaptchaValidator.parseCaptchaResponse logs this warning when the reCAPTCHA verification response contains a 'score' at or below the configured threshold (recaptchaProperties.getScore()). The validator returns false, so CAPTCHA validation fails even though the token may have been verified by Google.","triggerScenarios":"validate() -> parseCaptchaResponse() reads the verify-URL response JSON and finds node.score <= cas.googleRecaptcha.score; typical with reCAPTCHA v3 score-based verification.","commonSituations":"Threshold set too high for real-user traffic (v3 scores commonly fall between 0.3-0.9); suspicious/automated traffic producing low scores; response actually from reCAPTCHA v2 (no useful score semantics) being checked against a v3 threshold.","solutions":["Lower cas.googleRecaptcha.score (e.g. from 0.9 to 0.5) to accept typical human scores.","Confirm the site key/secret pair matches the intended reCAPTCHA version (v2 vs v3).","Inspect logged verification responses to see actual score distribution and adjust the threshold.","If scores are consistently ~0.1, investigate for bot traffic or misconfigured site key."],"exampleFix":"// before\ncas.googleRecaptcha.score=0.9\n// after\ncas.googleRecaptcha.score=0.5","handlingStrategy":"validation","validationCode":"// client: read the returned score logic; server: adjust threshold\nconst score = verifyResponse.score;\nif (score < 0.5) { requireStepUp(); }","typeGuard":"function hasScore(node: Record<string, unknown>): node is { score: number } {\n  return typeof node.score === 'number' && node.score >= 0 && node.score <= 1;\n}","tryCatchPattern":"boolean ok = captchaValidator.validate(token, userAgent);\nif (!ok) {\n  LOGGER.warn(\"reCAPTCHA validation failed (low score or unsuccessful)\");\n  return error(\"captcha-failed\");\n}","preventionTips":["Set cas.googleRecaptcha.score based on observed real-user score distribution, not assumptions.","Use a v2/v3 site key and secret pair consistent with the configured validator.","Log and monitor verification responses to tune the threshold over time.","Provide a fallback flow (e.g. email verification) for users unfairly rejected by low scores."],"tags":["recaptcha","captcha","validation"],"backgroundTag":"invalid-config-value","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}