<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shahraan Hussain</title>
    <description>The latest articles on DEV Community by Shahraan Hussain (@shahraan_hussain_b42640e7).</description>
    <link>https://dev.to/shahraan_hussain_b42640e7</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2558281%2F74643e2a-7c6d-489c-b67a-6eed2448489f.png</url>
      <title>DEV Community: Shahraan Hussain</title>
      <link>https://dev.to/shahraan_hussain_b42640e7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shahraan_hussain_b42640e7"/>
    <language>en</language>
    <item>
      <title>I Tested an Open-Source Anti-Bot Firewall (Anubis) Against Requests, AsyncIO, Selenium, and Playwright</title>
      <dc:creator>Shahraan Hussain</dc:creator>
      <pubDate>Mon, 22 Jun 2026 17:00:03 +0000</pubDate>
      <link>https://dev.to/shahraan_hussain_b42640e7/i-tested-an-open-source-anti-bot-firewall-anubis-against-requests-asyncio-selenium-and-2g0h</link>
      <guid>https://dev.to/shahraan_hussain_b42640e7/i-tested-an-open-source-anti-bot-firewall-anubis-against-requests-asyncio-selenium-and-2g0h</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftovyjmptnh0gdbfk69q6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftovyjmptnh0gdbfk69q6.png" alt=" " width="799" height="606"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lately I've been spending a lot of time studying modern anti-bot systems.&lt;/p&gt;

&lt;p&gt;Most discussions today revolve around Cloudflare, DataDome, Akamai, Kasada, Human Security, or PerimeterX. But while exploring the anti-bot ecosystem, I stumbled upon an interesting open-source project called &lt;strong&gt;Anubis&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Its description immediately caught my attention:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Anubis is a Web AI Firewall Utility that weighs the soul of your connection using one or more challenges in order to protect upstream resources from scraper bots."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The project was created to help smaller communities defend themselves against the massive amount of automated traffic generated by AI crawlers and large-scale scrapers.&lt;/p&gt;

&lt;p&gt;Naturally, I wanted to see how it behaved in practice.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Is Anubis?
&lt;/h1&gt;

&lt;p&gt;Anubis positions itself as a lightweight anti-bot layer that sits in front of websites and presents computational challenges to visitors before allowing access.&lt;/p&gt;

&lt;p&gt;The idea is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Legitimate users pass the challenge.&lt;/li&gt;
&lt;li&gt;Automated traffic gets filtered.&lt;/li&gt;
&lt;li&gt;Website resources are protected from abuse.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project openly states that it can be considered a "nuclear option" because it may block smaller scrapers and even impact beneficial crawlers such as Internet Archive bots.&lt;/p&gt;

&lt;p&gt;Unlike enterprise anti-bot vendors, Anubis focuses on simplicity and self-hosting.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Test Targets
&lt;/h1&gt;

&lt;p&gt;I found several publicly accessible websites running Anubis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://source.puri.sm/public" rel="noopener noreferrer"&gt;https://source.puri.sm/public&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bugs.winehq.org/" rel="noopener noreferrer"&gt;https://bugs.winehq.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://scioly.org/" rel="noopener noreferrer"&gt;https://scioly.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal wasn't to bypass anything.&lt;/p&gt;

&lt;p&gt;I simply wanted to understand:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens when common scraping tools interact with Anubis-protected websites?&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Experiment #1 — Plain Requests
&lt;/h1&gt;

&lt;p&gt;Like most scrapers, I started with the simplest possible setup.&lt;/p&gt;

&lt;p&gt;No browser.&lt;/p&gt;

&lt;p&gt;No JavaScript.&lt;/p&gt;

&lt;p&gt;No special headers.&lt;/p&gt;

&lt;p&gt;Just Python Requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;interval_start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://bugs.winehq.org/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;interval_end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status Code:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Interval &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;interval_end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;interval_start&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My expectation was straightforward.&lt;/p&gt;

&lt;p&gt;I thought I would see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;403 Forbidden
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or perhaps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;429 Too Many Requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead, every request returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;200 OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Twenty consecutive requests.&lt;/p&gt;

&lt;p&gt;Same IP.&lt;/p&gt;

&lt;p&gt;No proxy rotation.&lt;/p&gt;

&lt;p&gt;No browser fingerprinting.&lt;/p&gt;

&lt;p&gt;No TLS spoofing.&lt;/p&gt;

&lt;p&gt;Just Requests.&lt;/p&gt;




&lt;h1&gt;
  
  
  First Surprise
&lt;/h1&gt;

&lt;p&gt;At this point I became suspicious.&lt;/p&gt;

&lt;p&gt;Many anti-bot solutions allow a few requests before escalating defenses.&lt;/p&gt;

&lt;p&gt;So I wondered:&lt;/p&gt;

&lt;p&gt;Maybe Anubis is tracking request frequency.&lt;/p&gt;

&lt;p&gt;Maybe rate limits trigger after a threshold.&lt;/p&gt;

&lt;p&gt;Maybe concurrent traffic changes the outcome.&lt;/p&gt;

&lt;p&gt;So I moved to the next test.&lt;/p&gt;




&lt;h1&gt;
  
  
  Experiment #2 — 100 Concurrent Requests
&lt;/h1&gt;

&lt;p&gt;I used aiohttp to generate 100 simultaneous requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;aiohttp&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://bugs.winehq.org/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;req&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;aiohttp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ClientSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, I expected something to happen.&lt;/p&gt;

&lt;p&gt;Potential outcomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Challenge escalation&lt;/li&gt;
&lt;li&gt;Temporary blocking&lt;/li&gt;
&lt;li&gt;Connection throttling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result?&lt;/p&gt;

&lt;p&gt;Every request eventually completed successfully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100 requests
100 x 200 OK
0 blocks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some requests took longer than others, but they all succeeded.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Same IP the Entire Time
&lt;/h1&gt;

&lt;p&gt;One important detail:&lt;/p&gt;

&lt;p&gt;I never changed IP addresses.&lt;/p&gt;

&lt;p&gt;Throughout the experiment I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requests&lt;/li&gt;
&lt;li&gt;AsyncIO&lt;/li&gt;
&lt;li&gt;Selenium&lt;/li&gt;
&lt;li&gt;Playwright&lt;/li&gt;
&lt;li&gt;Playwright MCP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;all from the same IP.&lt;/p&gt;

&lt;p&gt;This is significant because IP reputation is often one of the earliest signals used by anti-bot systems.&lt;/p&gt;

&lt;p&gt;Repeated requests from the same source can contribute to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reputation scoring&lt;/li&gt;
&lt;li&gt;Velocity analysis&lt;/li&gt;
&lt;li&gt;Abuse detection&lt;/li&gt;
&lt;li&gt;Challenge escalation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yet I continued receiving successful responses.&lt;/p&gt;




&lt;h1&gt;
  
  
  Experiment #3 — Selenium
&lt;/h1&gt;

&lt;p&gt;At this point I assumed browser automation would be more likely to trigger protections.&lt;/p&gt;

&lt;p&gt;I launched Selenium.&lt;/p&gt;

&lt;p&gt;The browser displayed the familiar message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Chrome is being controlled by automated test software
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0hqlgjyrqrk48lzybjw5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0hqlgjyrqrk48lzybjw5.png" alt=" " width="800" height="610"&gt;&lt;/a&gt;&lt;br&gt;
which many anti-bot vendors actively monitor.&lt;/p&gt;

&lt;p&gt;The outcome?&lt;/p&gt;

&lt;p&gt;Normal page access.&lt;/p&gt;

&lt;p&gt;No obvious blocking.&lt;/p&gt;

&lt;p&gt;No visible challenge failure.&lt;/p&gt;


&lt;h1&gt;
  
  
  Experiment #4 — Playwright
&lt;/h1&gt;

&lt;p&gt;Next came Playwright.&lt;/p&gt;

&lt;p&gt;Playwright generally provides a more realistic browser environment and is often used when anti-bot protections become stricter.&lt;/p&gt;

&lt;p&gt;The result remained the same.&lt;/p&gt;

&lt;p&gt;Successful page loads.&lt;/p&gt;

&lt;p&gt;No visible enforcement action.&lt;/p&gt;


&lt;h1&gt;
  
  
  Experiment #5 — Playwright MCP
&lt;/h1&gt;

&lt;p&gt;Finally, I tested using Playwright MCP.&lt;/p&gt;

&lt;p&gt;Again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Success
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Anubis challenge completed successfully and access was granted.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Does This Mean?
&lt;/h1&gt;

&lt;p&gt;The most important takeaway is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A 200 response does not automatically mean the anti-bot system failed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are multiple possible explanations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Possibility 1: Conservative Configuration
&lt;/h3&gt;

&lt;p&gt;The websites may be running relatively relaxed Anubis settings.&lt;/p&gt;

&lt;p&gt;Many administrators prioritize accessibility over aggressive enforcement.&lt;/p&gt;




&lt;h3&gt;
  
  
  Possibility 2: Challenge Completion
&lt;/h3&gt;

&lt;p&gt;The requests may have successfully completed the challenge process without triggering additional scrutiny.&lt;/p&gt;




&lt;h3&gt;
  
  
  Possibility 3: Enforcement Thresholds Were Not Reached
&lt;/h3&gt;

&lt;p&gt;Anubis may require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Larger traffic volumes&lt;/li&gt;
&lt;li&gt;Longer observation windows&lt;/li&gt;
&lt;li&gt;Different behavioral patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;before escalating protections.&lt;/p&gt;




&lt;h3&gt;
  
  
  Possibility 4: Configuration Gaps
&lt;/h3&gt;

&lt;p&gt;Like any security product, deployment configuration matters.&lt;/p&gt;

&lt;p&gt;A protection layer can only be as effective as the rules applied to it.&lt;/p&gt;




&lt;h3&gt;
  
  
  Possibility 5: Areas for Future Improvement
&lt;/h3&gt;

&lt;p&gt;Every anti-bot solution evolves over time.&lt;/p&gt;

&lt;p&gt;Open-source projects especially benefit from community testing and feedback.&lt;/p&gt;

&lt;p&gt;Experiments like this can help identify edge cases and potential improvements.&lt;/p&gt;




&lt;h1&gt;
  
  
  What I'm Going To Test Next
&lt;/h1&gt;

&lt;p&gt;Rather than speculate, I plan to deploy my own Anubis-protected environment.&lt;/p&gt;

&lt;p&gt;That will allow controlled testing of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request-based scraping&lt;/li&gt;
&lt;li&gt;Browser automation&lt;/li&gt;
&lt;li&gt;TLS fingerprints&lt;/li&gt;
&lt;li&gt;Header anomalies&lt;/li&gt;
&lt;li&gt;Concurrency limits&lt;/li&gt;
&lt;li&gt;IP reputation&lt;/li&gt;
&lt;li&gt;Behavioral analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only then can I determine whether what I observed was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A configuration choice&lt;/li&gt;
&lt;li&gt;A deployment-specific behavior&lt;/li&gt;
&lt;li&gt;An intentional design decision&lt;/li&gt;
&lt;li&gt;Or an area that deserves further investigation&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Final Thoughts
&lt;/h1&gt;

&lt;p&gt;One thing I've learned after years of working in web scraping:&lt;/p&gt;

&lt;p&gt;Never underestimate an anti-bot system.&lt;/p&gt;

&lt;p&gt;A successful request today doesn't mean a defense is weak.&lt;/p&gt;

&lt;p&gt;Likewise, a blocked request doesn't necessarily mean a defense is strong.&lt;/p&gt;

&lt;p&gt;The interesting part is understanding &lt;em&gt;why&lt;/em&gt; a request succeeds or fails.&lt;/p&gt;

&lt;p&gt;This experiment raised more questions than answers—which is exactly what makes anti-bot research fascinating.&lt;/p&gt;

&lt;p&gt;The next step is building a controlled environment and digging deeper into how Anubis evaluates connections, challenges clients, and decides who gets through.&lt;/p&gt;

&lt;p&gt;And honestly, that's where the fun begins.&lt;/p&gt;

&lt;h1&gt;
  
  
  WebScraping #DataExtraction #BotDetection #AntiScraping #SecurityFail #DevOps #WebSecurity #CyberSecurity #BotDefense #ScraperLife
&lt;/h1&gt;

</description>
      <category>antibot</category>
      <category>firewall</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Anti-Bot Evasion 2026: Why Your TLS Handshake Is Getting You Flagged (And How to Fix It)</title>
      <dc:creator>Shahraan Hussain</dc:creator>
      <pubDate>Sun, 21 Jun 2026 11:05:06 +0000</pubDate>
      <link>https://dev.to/shahraan_hussain_b42640e7/anti-bot-evasion-2026-why-your-tls-handshake-is-getting-you-flagged-and-how-to-fix-it-4cmn</link>
      <guid>https://dev.to/shahraan_hussain_b42640e7/anti-bot-evasion-2026-why-your-tls-handshake-is-getting-you-flagged-and-how-to-fix-it-4cmn</guid>
      <description>&lt;h1&gt;
  
  
  Why Your Browser Version Could Be Exposing Your Scraper Before the First Request
&lt;/h1&gt;

&lt;p&gt;Modern anti-bot systems no longer rely solely on HTTP headers, JavaScript fingerprints, or IP reputation. Increasingly, detection begins before the first HTTP request is even processed—during the TLS handshake itself.&lt;/p&gt;

&lt;p&gt;One signal that has become difficult to ignore is the rise of Post-Quantum (PQ) key exchange support in modern browsers.&lt;/p&gt;

&lt;p&gt;Recently, I ran a series of tests to understand how this affects browser impersonation and scraping infrastructure. The results were interesting.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Evolution of Browser Fingerprinting
&lt;/h2&gt;

&lt;p&gt;For years, many scraping tools focused on matching:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User-Agent strings&lt;/li&gt;
&lt;li&gt;HTTP headers&lt;/li&gt;
&lt;li&gt;Browser APIs&lt;/li&gt;
&lt;li&gt;Canvas and WebGL fingerprints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, anti-bot vendors have steadily moved lower in the networking stack.&lt;/p&gt;

&lt;p&gt;Today, platforms such as Cloudflare, Akamai, DataDome, Kasada, and others analyze signals including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TLS ClientHello fingerprints&lt;/li&gt;
&lt;li&gt;Cipher suite ordering&lt;/li&gt;
&lt;li&gt;TLS extension ordering&lt;/li&gt;
&lt;li&gt;JA3 and JA4 fingerprints&lt;/li&gt;
&lt;li&gt;HTTP/2 SETTINGS fingerprints&lt;/li&gt;
&lt;li&gt;HTTP/3 and QUIC characteristics&lt;/li&gt;
&lt;li&gt;Browser behavior consistency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means that claiming to be Chrome 149 while presenting a TLS handshake that looks nothing like Chrome 149 can immediately increase suspicion.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Post-Quantum Shift
&lt;/h2&gt;

&lt;p&gt;Recent browser versions have started deploying hybrid post-quantum key exchanges.&lt;/p&gt;

&lt;p&gt;A commonly observed example is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;X25519MLKEM768
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This hybrid mechanism combines traditional elliptic-curve cryptography with post-quantum cryptographic protection.&lt;/p&gt;

&lt;p&gt;From an anti-bot perspective, the important observation is simple:&lt;/p&gt;

&lt;p&gt;If a client claims to be a modern browser but does not exhibit characteristics commonly associated with that browser generation, it becomes easier to identify inconsistencies.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Simple Experiment
&lt;/h2&gt;

&lt;p&gt;To explore this, I tested a modern browser impersonation stack and inspected the negotiated connection details using Cloudflare's trace endpoint.&lt;/p&gt;

&lt;p&gt;The response included:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tls=TLSv1.3
http=http/2
kex=X25519MLKEM768
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interesting field here is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kex=X25519MLKEM768
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which indicates that a post-quantum hybrid key exchange was successfully negotiated.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;Consider two clients:&lt;/p&gt;

&lt;h3&gt;
  
  
  Client A
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User-Agent: Chrome 149
TLS Key Share: X25519 only
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Client B
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User-Agent: Chrome 149
TLS Key Share: X25519MLKEM768
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neither signal alone determines whether the client is a bot.&lt;/p&gt;

&lt;p&gt;However, modern anti-bot systems are built around consistency.&lt;/p&gt;

&lt;p&gt;When every layer of the connection aligns with what is expected from a real browser, the overall risk score tends to improve.&lt;/p&gt;

&lt;p&gt;When multiple inconsistencies accumulate, the opposite happens.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Common Misconception
&lt;/h2&gt;

&lt;p&gt;Many engineers assume that bypassing anti-bot systems is primarily about headers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User-Agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Chrome/149&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, that approach stopped being sufficient years ago.&lt;/p&gt;

&lt;p&gt;Today, anti-bot systems may inspect:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;TLS fingerprints&lt;/li&gt;
&lt;li&gt;HTTP/2 fingerprints&lt;/li&gt;
&lt;li&gt;HTTP/3 fingerprints&lt;/li&gt;
&lt;li&gt;Browser APIs&lt;/li&gt;
&lt;li&gt;Behavioral signals&lt;/li&gt;
&lt;li&gt;Session history&lt;/li&gt;
&lt;li&gt;IP reputation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;TLS is only one layer, but it is often the first layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing Modern TLS Profiles
&lt;/h2&gt;

&lt;p&gt;When validating a browser impersonation stack, I now check:&lt;/p&gt;

&lt;h3&gt;
  
  
  TLS Layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Cipher suite ordering&lt;/li&gt;
&lt;li&gt;Extension ordering&lt;/li&gt;
&lt;li&gt;Supported groups&lt;/li&gt;
&lt;li&gt;Signature algorithms&lt;/li&gt;
&lt;li&gt;PQ key share support&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  HTTP Layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;HTTP/2 SETTINGS frames&lt;/li&gt;
&lt;li&gt;Header ordering&lt;/li&gt;
&lt;li&gt;Priority behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Browser Layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Navigator properties&lt;/li&gt;
&lt;li&gt;WebGL&lt;/li&gt;
&lt;li&gt;Canvas&lt;/li&gt;
&lt;li&gt;Audio fingerprints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A mismatch at any layer can become a useful signal for detection systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Does NOT Mean
&lt;/h2&gt;

&lt;p&gt;It's important not to overstate the impact.&lt;/p&gt;

&lt;p&gt;The absence of a PQ key share does not automatically mean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No PQ = Blocked
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Real-world traffic includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Older browsers&lt;/li&gt;
&lt;li&gt;Enterprise-managed devices&lt;/li&gt;
&lt;li&gt;Corporate TLS proxies&lt;/li&gt;
&lt;li&gt;Embedded browsers&lt;/li&gt;
&lt;li&gt;Mobile WebViews&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Blocking solely on PQ support would generate too many false positives.&lt;/p&gt;

&lt;p&gt;A more accurate conclusion is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The absence of a post-quantum key share is becoming an increasingly useful negative signal when a client claims to be a recent browser version.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Practical Takeaways
&lt;/h2&gt;

&lt;p&gt;If you're building browser impersonation or scraping infrastructure:&lt;/p&gt;

&lt;h3&gt;
  
  
  Review Your TLS Stack
&lt;/h3&gt;

&lt;p&gt;Verify that your TLS implementation matches the browser version you claim to emulate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stop Focusing Only on Headers
&lt;/h3&gt;

&lt;p&gt;Headers are just one component of a much larger fingerprint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validate End-to-End Consistency
&lt;/h3&gt;

&lt;p&gt;The goal isn't merely to send a modern User-Agent.&lt;/p&gt;

&lt;p&gt;The goal is to make every layer of the connection look consistent with that User-Agent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitor Browser Changes
&lt;/h3&gt;

&lt;p&gt;Browser fingerprints evolve continuously.&lt;/p&gt;

&lt;p&gt;A profile that looked authentic six months ago may now be outdated.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Anti-bot detection continues to move deeper into the networking stack.&lt;/p&gt;

&lt;p&gt;While Post-Quantum key exchanges are not a magic bypass, they are becoming part of the broader fingerprint expected from modern browsers.&lt;/p&gt;

&lt;p&gt;For scraping engineers, the lesson is straightforward:&lt;/p&gt;

&lt;p&gt;The challenge is no longer making your headers look like Chrome.&lt;/p&gt;

&lt;p&gt;The challenge is making your entire connection behave like Chrome.&lt;/p&gt;

&lt;p&gt;And increasingly, that starts with the TLS handshake.&lt;/p&gt;

&lt;h1&gt;
  
  
  webscraping #antibot #cybersecurity #tls #cloudflare #postquantum #python #golang #devops #programming #antibotbypass
&lt;/h1&gt;

</description>
      <category>security</category>
      <category>learning</category>
      <category>dataengineering</category>
      <category>networking</category>
    </item>
    <item>
      <title>Can an AI Agent Behave Like a Human? A 12-Hour Experiment with StoryCaptcha</title>
      <dc:creator>Shahraan Hussain</dc:creator>
      <pubDate>Thu, 18 Jun 2026 13:33:46 +0000</pubDate>
      <link>https://dev.to/shahraan_hussain_b42640e7/can-an-ai-agent-behave-like-a-human-a-12-hour-experiment-with-storycaptcha-1661</link>
      <guid>https://dev.to/shahraan_hussain_b42640e7/can-an-ai-agent-behave-like-a-human-a-12-hour-experiment-with-storycaptcha-1661</guid>
      <description>&lt;p&gt;A day ago, I came across a LinkedIn post from Tyler Richards showcasing an experimental CAPTCHA called StoryCaptcha.&lt;/p&gt;

&lt;p&gt;The concept was simple but unusual.&lt;/p&gt;

&lt;p&gt;Instead of asking users to identify traffic lights or solve image puzzles, StoryCaptcha asks users to write a short story based on a random prompt and then evaluates the interaction using behavioral signals.&lt;/p&gt;

&lt;p&gt;The goal wasn't to build a production-ready CAPTCHA.&lt;/p&gt;

&lt;p&gt;It was an experiment exploring behavioral biometrics and user interaction patterns.&lt;/p&gt;

&lt;p&gt;As someone working in web scraping and anti-bot research, I immediately became curious.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens when an AI agent attempts the challenge?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;More importantly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can an AI-controlled browser generate interaction patterns that a behavioral CAPTCHA considers human?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I spent the next 12 hours trying to answer that question.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;For this experiment I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Playwright MCP&lt;/li&gt;
&lt;li&gt;VS Code&lt;/li&gt;
&lt;li&gt;GitHub Copilot&lt;/li&gt;
&lt;li&gt;Chromium&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The objective wasn't to bypass the CAPTCHA.&lt;/p&gt;

&lt;p&gt;The objective was to understand how a behavioral scoring system evaluates AI-driven interactions.&lt;/p&gt;




&lt;h2&gt;
  
  
  First Attempt: 56/100
&lt;/h2&gt;

&lt;p&gt;My first run scored 56/100 and failed.&lt;/p&gt;

&lt;p&gt;The reason quickly became obvious.&lt;/p&gt;

&lt;p&gt;The AI agent was behaving exactly how an automation system would behave:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copying and pasting content&lt;/li&gt;
&lt;li&gt;Completing actions immediately&lt;/li&gt;
&lt;li&gt;Following deterministic patterns&lt;/li&gt;
&lt;li&gt;Showing almost no hesitation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Efficient.&lt;/p&gt;

&lt;p&gt;But not very human.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Interesting Part
&lt;/h2&gt;

&lt;p&gt;Unlike many behavioral systems, StoryCaptcha actually exposes a large portion of the signals it evaluates.&lt;/p&gt;

&lt;p&gt;The dashboard displayed metrics such as:&lt;/p&gt;

&lt;h3&gt;
  
  
  Typing Signals
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Typed vs Pasted&lt;/li&gt;
&lt;li&gt;Keystrokes per character&lt;/li&gt;
&lt;li&gt;Key-hold (dwell) profile&lt;/li&gt;
&lt;li&gt;Key-overlap (rollover)&lt;/li&gt;
&lt;li&gt;Rhythm variability&lt;/li&gt;
&lt;li&gt;Non-repeating intervals&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Behavioral Signals
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Cognitive pauses&lt;/li&gt;
&lt;li&gt;Inter-interaction timing&lt;/li&gt;
&lt;li&gt;Correction behavior&lt;/li&gt;
&lt;li&gt;Backspace usage&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mouse Signals
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Mouse path curvature&lt;/li&gt;
&lt;li&gt;Straightness&lt;/li&gt;
&lt;li&gt;Teleport detection&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Content Signals
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Reads like language&lt;/li&gt;
&lt;li&gt;On-topic for prompt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This transformed the experiment from simple testing into a feedback-driven behavioral analysis exercise.&lt;/p&gt;

&lt;p&gt;Instead of guessing blindly, I could observe which signals were being evaluated and adjust the agent's behavior accordingly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Observation #1: Copy-Paste Was a Dead Giveaway
&lt;/h2&gt;

&lt;p&gt;Initially the AI agent preferred copying and pasting the story.&lt;/p&gt;

&lt;p&gt;StoryCaptcha immediately detected this.&lt;/p&gt;

&lt;p&gt;The first optimization was simple:&lt;/p&gt;

&lt;p&gt;Instead of pasting content, I instructed the agent to type the response character by character.&lt;/p&gt;

&lt;p&gt;The score improved.&lt;/p&gt;




&lt;h2&gt;
  
  
  Observation #2: Human Typing Isn't Uniform
&lt;/h2&gt;

&lt;p&gt;The next issue was typing cadence.&lt;/p&gt;

&lt;p&gt;Humans don't type with perfectly consistent timing.&lt;/p&gt;

&lt;p&gt;Sometimes we pause.&lt;/p&gt;

&lt;p&gt;Sometimes we think.&lt;/p&gt;

&lt;p&gt;Sometimes we speed up.&lt;/p&gt;

&lt;p&gt;I instructed the agent to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use random keystroke delays&lt;/li&gt;
&lt;li&gt;Avoid identical intervals&lt;/li&gt;
&lt;li&gt;Pause naturally between thoughts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The score improved again.&lt;/p&gt;

&lt;p&gt;One metric I paid particular attention to was:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-Repeating Intervals&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;StoryCaptcha was actively measuring how repetitive the timing patterns were.&lt;/p&gt;




&lt;h2&gt;
  
  
  Observation #3: Humans Make Mistakes
&lt;/h2&gt;

&lt;p&gt;Humans aren't perfect typists.&lt;/p&gt;

&lt;p&gt;We:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Misspell words&lt;/li&gt;
&lt;li&gt;Hit incorrect keys&lt;/li&gt;
&lt;li&gt;Use backspace&lt;/li&gt;
&lt;li&gt;Correct ourselves&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Automation rarely does.&lt;/p&gt;

&lt;p&gt;So I instructed the agent to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Occasionally introduce spelling mistakes&lt;/li&gt;
&lt;li&gt;Use backspace corrections&lt;/li&gt;
&lt;li&gt;Continue naturally after correction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dashboard reflected these behaviors through correction metrics and the overall score improved.&lt;/p&gt;




&lt;h2&gt;
  
  
  Observation #4: Humans Don't Instantly Click Everything
&lt;/h2&gt;

&lt;p&gt;The agent was still too efficient.&lt;/p&gt;

&lt;p&gt;Humans typically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read content&lt;/li&gt;
&lt;li&gt;Hover over elements&lt;/li&gt;
&lt;li&gt;Pause before actions&lt;/li&gt;
&lt;li&gt;Explore pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I encouraged more natural cursor movement and hovering behavior.&lt;/p&gt;

&lt;p&gt;StoryCaptcha evaluates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mouse path curvature&lt;/li&gt;
&lt;li&gt;Teleport detection&lt;/li&gt;
&lt;li&gt;Interaction timing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So this adjustment had a measurable impact.&lt;/p&gt;




&lt;h2&gt;
  
  
  Observation #5: One Signal Refused To Cooperate
&lt;/h2&gt;

&lt;p&gt;The most fascinating metric was:&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Overlap (Rollover)
&lt;/h3&gt;

&lt;p&gt;StoryCaptcha reported:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Human ≈ 25%–50% overlap&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My agent consistently scored:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;0%&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even after improving almost every other metric.&lt;/p&gt;

&lt;p&gt;This was particularly interesting because it exposed a difference between simulated typing and real human keyboard behavior.&lt;/p&gt;

&lt;p&gt;Humans frequently begin pressing the next key before fully releasing the previous key.&lt;/p&gt;

&lt;p&gt;Many automation frameworks generate perfectly sequential key events.&lt;/p&gt;

&lt;p&gt;The CAPTCHA was successfully identifying that distinction.&lt;/p&gt;

&lt;p&gt;Despite scoring well overall, this remained one of the strongest indicators that the interaction was not genuinely human.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Result
&lt;/h2&gt;

&lt;p&gt;After roughly 10 experimental runs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attempt&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Initial&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intermediate&lt;/td&gt;
&lt;td&gt;60–70&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optimized&lt;/td&gt;
&lt;td&gt;76–77&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The challenge eventually passed consistently.&lt;/p&gt;

&lt;p&gt;However, the score wasn't the most valuable outcome.&lt;/p&gt;

&lt;p&gt;The real value was understanding how behavioral features influenced the evaluation.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Behavioral Biometrics Are More Than Mouse Movement
&lt;/h3&gt;

&lt;p&gt;Before this experiment, most discussions I encountered focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Browser fingerprints&lt;/li&gt;
&lt;li&gt;TLS fingerprints&lt;/li&gt;
&lt;li&gt;Device identification&lt;/li&gt;
&lt;li&gt;Network reputation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This experiment reminded me that behavior itself can become a powerful signal.&lt;/p&gt;

&lt;p&gt;Not just what actions occur.&lt;/p&gt;

&lt;p&gt;But how they occur.&lt;/p&gt;




&lt;h3&gt;
  
  
  AI Agents Create New Challenges
&lt;/h3&gt;

&lt;p&gt;Traditional automation focuses on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speed&lt;/li&gt;
&lt;li&gt;Efficiency&lt;/li&gt;
&lt;li&gt;Determinism&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI agents introduce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exploration&lt;/li&gt;
&lt;li&gt;Context awareness&lt;/li&gt;
&lt;li&gt;Adaptive behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As AI agents become more common, behavioral detection systems will likely become increasingly important.&lt;/p&gt;




&lt;h3&gt;
  
  
  Reverse Engineering Doesn't Always Require Source Code
&lt;/h3&gt;

&lt;p&gt;I never saw StoryCaptcha's implementation.&lt;/p&gt;

&lt;p&gt;I never saw its scoring algorithm.&lt;/p&gt;

&lt;p&gt;But by observing outputs, forming hypotheses, and iteratively adjusting behavior, I was still able to learn a surprising amount about what the system valued.&lt;/p&gt;

&lt;p&gt;That's one of the things I enjoy most about reverse engineering:&lt;/p&gt;

&lt;p&gt;Observe.&lt;/p&gt;

&lt;p&gt;Hypothesize.&lt;/p&gt;

&lt;p&gt;Test.&lt;/p&gt;

&lt;p&gt;Repeat.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I started this experiment asking:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can an AI agent behave like a human?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Twelve hours later, I think the more interesting question is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which parts of human behavior are hardest for machines to reproduce?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer, at least from this experiment, appears to be much more nuanced than simply moving a mouse or typing text.&lt;/p&gt;

&lt;p&gt;And that's exactly what made the exercise worth exploring.&lt;/p&gt;

&lt;h1&gt;
  
  
  antibotbypass #antibot #cybersecurity #webscraping
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>automation</category>
      <category>mcp</category>
    </item>
  </channel>
</rss>
