Securing my website Against AI Scrapers, Bots, and Brute Force Attacks

I found that nosistech.com was wide open in ways I had not thought about. No WAF rules. No login protection. XML-RPC sitting there like an unlocked back door. And a robots.txt that was doing some things correctly but missing critical declarations for the AI era we are actually living in.

Disclaimer: This article documents a personal technical experiment on my own infrastructure. The configurations, rules, and steps described reflect what worked in my specific environment and should not be treated as security advice, professional recommendations, or guaranteed protection against any threat. Every environment is different. Always validate independently, test in a non-production setting first, and consult qualified security professionals before applying any security-related configuration to production systems. NosisTech LLC accepts no liability for outcomes resulting from use of this content.

The robots.txt file

I was looking at nosistech.com/robots.txt and the first thing I noticed was the Content-Signal header at the top. Cloudflare had added this automatically when I enabled their AI Crawl Control feature. The declaration reads search=yes and ai-train=no. What that means in plain language is that I am telling crawlers they can index my site for search results but they cannot scrape my content to train AI models.

That part was correct and I am glad it was there. But there was a gap.

The ai-input signal was undefined. That is the signal that covers real-time AI retrieval — meaning systems like Perplexity, ChatGPT’s browsing mode, and Claude’s web search that pull content live from your site to generate answers. I had not declared a position on that at all, which under the Content-Signal framework means I had neither granted nor restricted permission for it.

I spent some time thinking about what the right decision was. The honest answer is that it depends on what each site owner wants their site to do — I had to think through my own priorities before deciding.

So I made a deliberate decision to leave ai-input undefined and allow real-time retrieval crawlers through, while keeping training crawlers blocked. The distinction matters and I will explain it once more because it is not obvious. Training crawlers like GPTBot and CCBot scrape your content to permanently absorb it into model weights, with no attribution ever. Real-time retrieval crawlers fetch your content live, summarize it for a user, and cite the source URL in the answer. One takes without giving. The other gives you visibility in exchange for the summarization.

The bot blocking in my robots.txt covered Amazonbot, Applebot-Extended, Bytespider, CCBot, ClaudeBot, CloudflareBrowserRenderingCrawler, Google-Extended, GPTBot, and meta-externalagent. Each of these is blocked for a specific reason. CCBot is the most important one to block — it powers Common Crawl, which is the training dataset foundation for most open source large language models ever built. Your content being in Common Crawl means it ends up in training data for virtually every model without attribution or compensation.

Bytespider deserves a specific mention from a security perspective. That is ByteDance’s crawler — TikTok’s parent company — and it is subject to China’s National Intelligence Law, which requires cooperation with state intelligence agencies. It stays blocked.

The one I want to flag specifically is CloudflareBrowserRenderingCrawler. I initially thought this might be a Cloudflare infrastructure crawler serving my own site and considered unblocking it. After researching it properly I found that it is actually a public developer API that any Cloudflare account holder can use to scrape websites. It is not serving nosistech.com in any way. It stays blocked. That was an almost-mistake that research corrected before I acted on it.

One bot that was missing from my robots.txt was OAI-SearchBot. Most people know about GPTBot, which is OpenAI’s training crawler. What fewer people know is that OpenAI has a separate crawler specifically for ChatGPT’s search results feature. GPTBot trains the model. OAI-SearchBot powers live search citations. If you block GPTBot but don’t mention OAI-SearchBot, you are blocking training but still allowing search citations — which for most content sites is actually the correct configuration. I left OAI-SearchBot unblocked intentionally.

Now the security section

I pulled up my Cloudflare dashboard and went to Security then Security Rules. The screen showed: Custom rules 0/5 used. Rate limiting rules 0/1 used.

Zero rules. On a live WordPress site that had been running for months.

Let me explain what that means practically. WordPress sites have two endpoints that attackers target constantly. The first is wp-login.php, which is the admin login page. Every WordPress installation in the world has this exact URL, which means every bot hunting for weak WordPress credentials knows exactly where to go. The second is xmlrpc.php, a legacy feature that most WordPress sites no longer need but which remains active by default. Attackers abuse xmlrpc.php specifically because one request to it can test hundreds of username and password combinations simultaneously, effectively multiplying their brute force speed by several hundred times.

Both of these endpoints were completely unprotected. No challenge, no block, no rate limiting. Anything with an internet connection could hammer them indefinitely.

I also checked whether a WordPress security plugin was installed. There was none. So the only line of defense was whatever Cloudflare’s default behavior provided, which without explicit rules is essentially nothing for targeted endpoint attacks.

I created three rules.

The first blocks xmlrpc.php entirely at Cloudflare’s edge. The expression is simple: URI Path equals /xmlrpc.php, action Block. In my setup, requests to that endpoint no longer reach my server — they are stopped at Cloudflare’s network before WordPress sees them.

The second rule applies a Managed Challenge to wp-login.php. I want to explain why I used Managed Challenge here instead of Block. If I blocked wp-login.php completely I would lock myself out of my own admin panel. Managed Challenge is Cloudflare’s smart verification layer — it presents an invisible browser integrity check that real human browsers pass automatically in milliseconds without seeing any CAPTCHA. Automated bots fail it and never reach the login page. From my perspective, logging in feels exactly the same as before. In my experience, this configuration made the login page effectively unreachable for automated bots — though results will vary depending on your specific environment.

The third rule is rate limiting. I set it to block any IP that hits wp-login.php more than a set number of times in a certain time period. Credential stuffing bots fire hundreds of requests per second. In my assessment, getting blocked after a set number of attempts and having to wait resets automated bots constantly and made credential stuffing significantly harder to sustain against my setup.

After deploying the Cloudflare rules I went into WordPress and added a second layer of xmlrpc protection using WPCode Lite, which was already installed on my site. This is called defense in depth — two locks on the same door. The code is a single PHP line:

add_filter(‘xmlrpc_enabled’, ‘__return_false’);

I want to mention the mistake here. When I first tried to use WPCode’s pre-built Disable XML-RPC snippet from their library, I ended up with a blank untitled HTML snippet saved to my site instead of the actual PHP snippet. I am not entirely sure what happened — I think I clicked through too fast and it opened a new blank snippet instead of applying the library one. I caught it quickly, deleted the blank snippet, and created the correct PHP snippet from scratch. The lesson is to slow down and screenshot each step. This kind of thing happens and it is not catastrophic as long as you notice it.

The attribution infrastructure

The question I kept coming back to was whether there is any way to force AI systems to cite you when they use your content. The honest answer is no. There is no technical mechanism that compels citation. Once content is absorbed into model training weights there is no watermark that survives. For real-time retrieval, whether a system cites you depends entirely on how it is programmed, not on anything you control on your end.

What I focused on was making my content the obvious choice to cite voluntarily, and embedding my identity deeply enough in my content’s metadata that when citation does happen my name travels with it automatically.

I added Article schema markup to every post on nosistech.com via WPCode Lite. This is structured data embedded in each page’s HTML header that declares the author as Carlos A. Paredes Vargas, the publisher as NosisTech LLC, and references the Terms of Use page as the content license. When AI systems that do real-time retrieval parse my pages, that metadata is there telling them who wrote this and where it came from.

I also published a Terms of Use page at nosistech.com/terms-of-use. This does two things. First it gives the schema markup a license URL to reference, which is part of making the structured data complete and credible. Second it creates a formal legal record of my content rights declarations, including the AI training prohibition and the attribution requirement for any permitted use.

At the Cloudflare layer: xmlrpc.php is fully blocked in my setup, wp-login.php is behind a Managed Challenge with rate limiting, and AI Crawl Control is active with training bots blocked and real-time retrieval bots allowed.

At the WordPress layer: XML-RPC is disabled via PHP filter, Article schema markup is active on all posts, and a Terms of Use page is published and indexed.

At the search infrastructure layer: Google Search Console is connected, Bing Webmaster Tools is connected, and IndexNow is automatically submitting every new URL across both.

None of this required a paid Cloudflare plan. None of it required a premium WordPress security plugin. The free plan gives you five custom WAF rules and one rate limiting rule, which was enough to cover the critical attack surface for my WordPress setup.

WEEKLY BUILD NOTES

One documented agent build in your inbox, every week

Real systems, real code, the errors left in. No spam, unsubscribe anytime.