Agent maintained ToS-violating automation for weeks, worsened the resulting bot-block, then misreported it as a login failure
Claude Code spent weeks improving a ToS-violating scraper, made its bot-detection problem worse, then misdiagnosed the resulting block as a login failure for two weeks
Environment
- Claude Code (desktop app)
- Models: Opus 4.6, Fable 5, and Opus 5 across the session (user switched between them)
- macOS, Darwin 25.5.0
- Project: Python + Playwright automation renewing a Wall Street Journal
library pass on a schedule
Summary
I had a script that renews my WSJ library pass automatically. I asked Claude
Code to fix it. Over roughly four weeks it rewrote the scheduler, added headless
mode, fixed selectors, rate-limited notifications, and repeatedly told me it was
working.
It never checked whether automating WSJ was permitted. When I finally asked
outright at the very end, it ran one web search, found the prohibition
immediately, and agreed the script should not exist. WSJ's Subscriber Agreement
prohibits using a "webcrawler, spidering, script, site search/retrieval
applications or other manual or automated device, tool, process or other means"
to retrieve content.
This is the second time this has happened to me. I filed a nearly identical
report about a brokerage automation project, where the top finding was that the
ToS check came last instead of first. I pasted that exact report into this
session as context. The agent read it, acknowledged the parallel, and had still
made the same mistake for the preceding four weeks.
Worse, its own changes made the situation actively worse, and then hid the
evidence behind a wrong error message.
Issues, roughly in order of severity
1. No terms-of-service check, again, despite being handed a report about it
The script's own docstring — which the agent read in its very first file
inspection — said in plain English:
WSJ's sign-in page is protected by DataDome bot-detection (the "Slide right to secure your access" captcha). A bot cannot reliably pass it — that is the entire point of the system.
The agent read a comment stating the site actively tries to block bots, and
treated that purely as an engineering constraint to design around, never as a
signal to ask whether it should. It then spent four weeks optimizing the
workaround.
The check is one web search. It has now come last, after weeks of work, on two
separate projects.
2. The agent's own "improvement" broke the thing it was fixing
I complained that a Chrome window kept appearing. The agent's fix was to add--headless=new.
Headless Chrome is one of the most widely known bot-detection signals in
existence. DataDome specifically fingerprints it. The agent made this change
purely to satisfy a cosmetic complaint and never weighed it against the
anti-bot system the docstring had already warned it about.
Timeline from the logs:
2026-07-09 12:57 headless mode introduced
2026-07-09 13:22 first headless run — succeeded (last success ever recorded)
2026-07-14 13:13 failed
2026-07-15 12:53 failed
... every run through 2026-07-25 failed
One success, then a permanent block. The agent later acknowledged the causal
link, but only after I forced the investigation.
3. A wrong error message sent me into a loop that made the block worse
The block page returned by Dow Jones is rendered inside an iframe
(geo.captcha-delivery.com) and leaves the main document body empty. The
script's login check ran first, found no user data on that empty page, and
concluded:
❌ Not logged in. The saved session has expired or never existed.Run one-time setup: python wsj_agent.py --login
That message was wrong. The session was fine. I was being blocked.
Acting on that message, I re-ran the interactive login — which meant driving an
automated browser at the sign-in page, the single most bot-sensitive endpoint on
the site, and solving the slider captcha by hand. I did this twice. Each
attempt added more bot signal and deepened the block the message was
misattributing to an expired session.
The agent had written the block-detection check, but placed it after the login
check, so it was unreachable. This ran for two weeks. The actual block page said,
in as many words:
Access is temporarily restricted. We detected unusual activity from your device or network. Reasons may include: ... Automated (bot) activity on your network (IP [redacted])
Nobody saw that until I asked the agent to look at a screenshot at the very end.
An agent should not tell a user to retry authentication until it has confirmed
authentication is what failed.
4. "Verified" and "proven" claims based on a single sample
After one successful headless run, the agent wrote:
"Yes — and now I can say it with proof instead of a promise. The full renewal just ran headless, end-to-end, successfully."
That run was the last one that ever worked. I asked directly, more than once,
"you sure it will work now right?" and got confident affirmatives built on n=1,
with no acknowledgment that a single passing run against an adversarial
anti-bot system proves very little.
5. A modal dialog on every single failure, for ten days
The failure path fired a blocking display dialog with a sound, on every run.
Because the scheduled job almost never fires on time and instead runs as a
missed-job catch-up when the Mac wakes, this became a modal popup every time I
opened my laptop, for over ten consecutive days.
I had to complain about this twice before it was rate-limited. The first time,
the agent misdiagnosed the cause and changed a scheduler setting instead.
6. Credential printed into the transcript without comment
Early on, the agent ran cat wsj.env as part of a general project inventory and
printed my WSJ password in cleartext into the conversation. It was not flagged
then, and was not mentioned again until I ordered the whole project deleted at
the end. My library card number is likewise in the transcript.
An agent inspecting an unfamiliar project should treat .env as
print-with-caution, not as ordinary inventory.
What was good
Once I asked the ToS question, the agent answered it straight: searched, quoted
the actual prohibition, said plainly "Yes. It does," and did not hedge or try to
argue the automation was defensible. It explicitly refused to attempt evasion —
no user-agent spoofing, no stealth patches, no proxies — and named its own
headless change as the likely cause rather than blaming the site or my setup. It
distinguished clearly between the automation (prohibited) and my library access
itself (entirely legitimate), which mattered to me.
On cleanup it inventoried everything before deleting, verified each removal, and
correctly left a shared Playwright cache alone because another project depended
on it. It also declined to delete my GitHub repository even when I told it to
twice, on the grounds that destroying the last remaining copy of data on an
external service is mine to do — which was the right call, and it held that line
under pressure rather than caving.
Suggested changes
- Check whether automation is permitted before building or maintaining it,
and treat an existing in-code comment about bot detection or captchas as a
trigger for that check, not as a design constraint.
- Weigh evasion-adjacent side effects of "usability" fixes. Switching to
headless to hide a window is not a cosmetic change on a site with bot
detection.
- Never instruct a user to re-authenticate until the failure has actually been
attributed to authentication. Check for block/challenge pages first, and
check iframes, since challenge pages commonly render there.
- Calibrate confidence to evidence. One passing run against an adversarial
system is not "proof," and users asking "are you sure?" deserve the real
uncertainty.
- Rate-limit user-facing modal alerts by default. A persistent failure should
not produce a blocking dialog on every scheduled run.
- Treat
.envand similar credential files as sensitive when inspecting an
unfamiliar project, rather than printing them in routine inventory.