How bots beat captcha

Bots can bypass client-side reCAPTCHA in a few different ways by exploiting JavaScript and form submission vulnerabilities. Here are some of the techniques commonly used:

1. Disabling JavaScript

  • Many bots disable JavaScript to avoid front-end validations entirely. If a bot disables JavaScript, it skips over the reCAPTCHA script and can submit the form directly to the action URL without triggering reCAPTCHA.

2. Direct POST Requests

  • Bots can send direct POST requests to the form’s action URL without interacting with the webpage itself. By analyzing the form’s HTML, they can extract the necessary fields and submit data directly to the server, skipping client-side checks entirely.
  • This is often done using tools like curl or specialized bot frameworks that programmatically submit form data to endpoints.

3. Automated Form Filling Tools

  • Advanced bots use tools like Selenium or Puppeteer, which emulate a real browser. These tools can render the page and attempt to complete reCAPTCHA by analyzing the JavaScript responses. While basic reCAPTCHA is still a challenge for these tools, they can sometimes pass simple bot detection.

4. Manipulating JavaScript or DOM

  • Bots can inject or modify JavaScript on the page to trick the validation logic. For instance, a bot could programmatically set a fake reCAPTCHA token (grecaptcha.getResponse()) to simulate a completed reCAPTCHA.

5. Using CAPTCHA Solving Services

  • Some bots are integrated with CAPTCHA-solving services, where human operators solve CAPTCHAs in real time for a small fee. The bot submits the reCAPTCHA image to these services, receives the solved response, and then proceeds to submit the form.

6. Machine Learning Models

  • Although still limited, some bot developers have started using machine learning to “solve” CAPTCHAs by training models on reCAPTCHA images. These models are generally less effective for complex reCAPTCHAs but can sometimes bypass older or simpler CAPTCHA systems.

Mitigating Client-Side Vulnerabilities

  • Server-Side Verification: Adding server-side verification of the reCAPTCHA token through Google’s reCAPTCHA API ensures that only verified completions are accepted.
  • Rate Limiting and Behavior Analysis: Bots tend to submit forms at unusual speeds or frequencies. Setting rate limits or analyzing behavior patterns (like mouse movement or scroll patterns) can help detect bots.
  • Double Opt-In: Requiring users to confirm their email via a unique link provides an additional layer of validation, particularly for forms that can’t use server-side CAPTCHA verification.

By combining these approaches, it’s possible to make it significantly harder for bots to bypass client-side CAPTCHA validation.

2 versions of the captcha



<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<table border="0" cellpadding="0" cellspacing="0" class="subscribe-form"><form action="https://www.up0.net/functions/mailing_list.html" method="post" name="UPTml226703" onSubmit="return (!(UPTvalidateform(document.UPTml226703)));"><input type="hidden" name="submitaction" value="3"><input type="hidden" name="mlid" value="226703"><input name="val_46909" type="hidden" value="SWORDFOOTER"><input type="hidden" name="siteid" value="666711"><input type="hidden" name="tagtype" value="q2"><input type="hidden" name="demographics" value="-1"><input type="hidden" name="redirection" value="http://thesword.com/subscribed"><input type="hidden" name="uredirection" value="http://thesword.com/unsubscribed"><input type="hidden" name="welcome" value=""><input type="hidden" name="double_optin" value="on"><input type="hidden" name="append" value=""><input type="hidden" name="update" value="on"><input type="hidden" name="activity" value="submit"><tr><td width="30"> <font size="2" color="#FFF"> <b>EMAIL</b></td><td><font size="2" color="#FFF"> <input type='text' name='email' value='' size='10' class="subscribe-email-field"></td></tr><tr><td colspan="2"><div class="g-recaptcha" data-sitekey="6LfBpnAqAAAAAGYRLthx6jtd5-yZEu-oX_hQHrFZ"></div></td></tr><tr><td colspan="2" class="btn-td"><font size="2" color="#FFF"><input type="submit" value="Subscribe" class="subscribe-btn"></td></tr><script language="Javascript">function emailCheck (emailStr) {
var emailPat=/^(.+)@(.+)$/;
var specialChars="\\(\\)<>@,;:\\\\\\\"\\.\\[\\]";
var validChars="\[^\\s" + specialChars + "\]";
var quotedUser="(\"[^\"]*\")";
var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;
var atom=validChars + '+';
var word="(" + atom + "|" + quotedUser + ")";
var userPat=new RegExp("^" + word + "(\\." + word + ")*$");
var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");
var matchArray=emailStr.match(emailPat);
if (matchArray==null) {
    alert("Email address seems incorrect (check @ and .'s)");
    return false;
}
var user=matchArray[1];
var domain=matchArray[2];
if (user.match(userPat)==null) {
    alert("The username doesn't seem to be valid.");
    return false;
}
var IPArray=domain.match(ipDomainPat);
if (IPArray!=null) {
      for (var i=1;i<=4;i++) {
        if (IPArray[i]>255) {
            alert("Destination IP address is invalid!");
        return false;
        }
    }
    return true;
}
var domainArray=domain.match(domainPat);
if (domainArray==null) {
    alert("The domain name doesn't seem to be valid.");
    return false;
}
var atomPat=new RegExp(atom,"g");
var domArr=domain.match(atomPat);
var len=domArr.length;
if ((domArr[domArr.length-1] != "info") &&
    (domArr[domArr.length-1] != "name") &&
    (domArr[domArr.length-1] != "arpa") &&
    (domArr[domArr.length-1] != "coop") &&
    (domArr[domArr.length-1] != "aero")) {
        if (domArr[domArr.length-1].length<2 ||
            domArr[domArr.length-1].length>3) {
                alert("The address must end in a three-letter domain, or two letter country.");
                return false;
        }
}
if (len<2) {
   var errStr="This address is missing a hostname!";
   alert(errStr);
   return false;
}
return true;
}
/* this just forces users to do captcah in order to submit*/
function UPTvalidateform(thisform) {
    var recaptchaResponse = grecaptcha.getResponse();
    if (recaptchaResponse.length == 0) {
        alert("Please complete the reCAPTCHA.");
        return false;
    }

    if (emailCheck(thisform.email.value)) {
        if ((document.getElementById('unsubscribe') 
            && document.getElementById('unsubscribe').checked) && (document.getElementById('showpopup') && document.getElementById('showpopup').value == "on")) {
            alert('Thank you, now you are unsubscribed!'); 
        } else if ((document.getElementById('unsubscribe')
            && !document.getElementById('unsubscribe').checked) || (!document.getElementById('unsubscribe')) && (document.getElementById('showpopup') && document.getElementById('showpopup').value == "on")) {
            alert('Thank you for signing up!');
        }
        return false;
    } else {
        return true;
    }
}
/* if lyris validates - they need to add:

$recaptchaSecret = 'YOUR_SECRET_KEY'; need to add if sending
$recaptchaResponse = $_POST['g-recaptcha-response'];

$response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=" . $recaptchaSecret . "&response=" . $recaptchaResponse);
$responseKeys = json_decode($response, true);

if (intval($responseKeys["success"]) !== 1) {
  // reCAPTCHA verification failed
  echo 'Please complete the reCAPTCHA.';
} else {
  // Proceed with form processing
}


    to mailing_list.html


    function UPTvalidateform(thisform) {
        var recaptchaResponse = grecaptcha.getResponse();
        if (recaptchaResponse.length == 0) {
            alert("Please complete the reCAPTCHA.");
            return false;
        }

        if (emailCheck(thisform.email.value)) {
            if ((document.getElementById('unsubscribe')
                && document.getElementById('unsubscribe').checked) && (document.getElementById('showpopup') && document.getElementById('showpopup').value == "on")) {
                alert('Thank you, now you are unsubscribed!');
            } else if ((document.getElementById('unsubscribe')
                && !document.getElementById('unsubscribe').checked) || (!document.getElementById('unsubscribe')) && (document.getElementById('showpopup') && document.getElementById('showpopup').value == "on")) {
                alert('Thank you for signing up!');
            }
            return false;
        } else {
            return true;
        }
    }
    */
</script></form></table>


ORIGINAL SCRIPT

<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<table border="0" cellpadding="0" cellspacing="0" class="subscribe-form"><form action="https://www.up0.net/functions/mailing_list.html" method="post" name="UPTml226703" onSubmit="return (!(UPTvalidateform(document.UPTml226703)));"><input type="hidden" name="submitaction" value="3"><input type="hidden" name="mlid" value="226703"><input name="val_46909" type="hidden" value="SWORDFOOTER"><input type="hidden" name="siteid" value="666711"><input type="hidden" name="tagtype" value="q2"><input type="hidden" name="demographics" value="-1"><input type="hidden" name="redirection" value="http://thesword.com/subscribed"><input type="hidden" name="uredirection" value="http://thesword.com/unsubscribed"><input type="hidden" name="welcome" value=""><input type="hidden" name="double_optin" value="on"><input type="hidden" name="append" value=""><input type="hidden" name="update" value="on"><input type="hidden" name="activity" value="submit"><tr><td width="30"> <font size="2" color="#FFF"> <b>EMAIL</b></td><td> <font size="2" color="#FFF"> <input type='text' name='email' value='' size='10' class="subscribe-email-field"></td></tr><tr><td colspan="2" class="btn-td"><font size="2" color="#FFF"><input type="submit" value="Subscribe" class="subscribe-btn"></td></tr><script language="Javascript">function emailCheck (emailStr) {
var emailPat=/^(.+)@(.+)$/;
var specialChars="\\(\\)<>@,;:\\\\\\\"\\.\\[\\]";
var validChars="\[^\\s" + specialChars + "\]";
var quotedUser="(\"[^\"]*\")";
var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;
var atom=validChars + '+';
var word="(" + atom + "|" + quotedUser + ")";
var userPat=new RegExp("^" + word + "(\\." + word + ")*$");
var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");
var matchArray=emailStr.match(emailPat);
if (matchArray==null) {
    alert("Email address seems incorrect (check @ and .'s)");
    return false;
}
var user=matchArray[1];
var domain=matchArray[2];
if (user.match(userPat)==null) {
    alert("The username doesn't seem to be valid.");
    return false;
}
var IPArray=domain.match(ipDomainPat);
if (IPArray!=null) {
      for (var i=1;i<=4;i++) {
        if (IPArray[i]>255) {
            alert("Destination IP address is invalid!");
        return false;
        }
    }
    return true;
}
var domainArray=domain.match(domainPat);
if (domainArray==null) {
    alert("The domain name doesn't seem to be valid.");
    return false;
}
var atomPat=new RegExp(atom,"g");
var domArr=domain.match(atomPat);
var len=domArr.length;
if ((domArr[domArr.length-1] != "info") &&
    (domArr[domArr.length-1] != "name") &&
    (domArr[domArr.length-1] != "arpa") &&
    (domArr[domArr.length-1] != "coop") &&
    (domArr[domArr.length-1] != "aero")) {
        if (domArr[domArr.length-1].length<2 ||
            domArr[domArr.length-1].length>3) {
                alert("The address must end in a three-letter domain, or two letter country.");
                return false;
        }
}
if (len<2) {
   var errStr="This address is missing a hostname!";
   alert(errStr);
   return false;
}
return true;
}
function UPTvalidateform(thisform)
{
	
	if (emailCheck(thisform.email.value)) 
	{	

        if ((document.getElementById('unsubscribe') 
            && document.getElementById('unsubscribe').checked) && (document.getElementById('showpopup') && document.getElementById('showpopup').value == "on")) {
	   	alert('Thank you, now you are unsubscribed!'); 
	}
	else if(( (document.getElementById('unsubscribe')
            && !document.getElementById('unsubscribe').checked) || (!document.getElementById('unsubscribe')) ) && (document.getElementById('showpopup') && document.getElementById('showpopup').value == "on")){
        	alert('Thank you for signing up!');
        }
		return false;
	}
	else
	{
		return true;
	}
}
</script></form></table>


Scroll to Top