惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google Online Security Blog
Google Online Security Blog
博客园_首页
酷 壳 – CoolShell
酷 壳 – CoolShell
Jina AI
Jina AI
博客园 - Franky
大猫的无限游戏
大猫的无限游戏
Hugging Face - Blog
Hugging Face - Blog
博客园 - 司徒正美
V
V2EX
雷峰网
雷峰网
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
F
Full Disclosure
Y
Y Combinator Blog
V
V2EX - 技术
Attack and Defense Labs
Attack and Defense Labs
S
Security @ Cisco Blogs
Schneier on Security
Schneier on Security
Microsoft Azure Blog
Microsoft Azure Blog
SecWiki News
SecWiki News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The GitHub Blog
The GitHub Blog
量子位
PCI Perspectives
PCI Perspectives
S
Secure Thoughts
D
Darknet – Hacking Tools, Hacker News & Cyber Security
AWS News Blog
AWS News Blog
Blog — PlanetScale
Blog — PlanetScale
爱范儿
爱范儿
K
Kaspersky official blog
B
Blog
A
Arctic Wolf
Hacker News: Ask HN
Hacker News: Ask HN
L
LangChain Blog
T
Tor Project blog
P
Privacy & Cybersecurity Law Blog
Recent Announcements
Recent Announcements
宝玉的分享
宝玉的分享
The Register - Security
The Register - Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
Lohrmann on Cybersecurity
D
Docker
A
About on SuperTechFans
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Google DeepMind News
Google DeepMind News
The Last Watchdog
The Last Watchdog
S
Security Affairs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Privacy International News Feed
Simon Willison's Weblog
Simon Willison's Weblog

Simon Willison's Weblog

Statement on the US government directive to suspend access to Fable 5 and Mythos 5 OpenAI WebRTC Audio Session, now with document context A quote from Andrew Singleton Release: datasette 1.0a33 Release: asyncinject 0.7 Anthropic Walks Back Policy That Could Have ‘Sabotaged’ AI Researchers Using Claude Release: datasette-agent 0.2a0 DiffusionGemma A quote from Jeremy Howard If Claude Fable stops helping you, you’ll never know Initial impressions of Claude Fable 5 Release: llm 0.32a3 TIL: Setting a custom price for a model in AgentsView A quote from Andrej Karpathy Siri AI at WWDC 2026 Release: datasette-agent-edit 0.1a0 Release: micropython-wasm 0.1a2 Running Python code in a sandbox with MicroPython and WASM OpenAI Help: Lockdown Mode A quote from Andreas Kling AI enthusiasts are in a race against time, AI skeptics are in a race against entropy A quote from Emanuel Maiberg, 404 Media Uber Caps Usage of AI Tools Like Claude Code to Manage Costs Microsoft's new MAI models Release: datasette-agent-micropython 0.1a0 Release: micropython-wasm 0.1a1 Sighting: California Brown Pelican Tool: Pasted File Editor Release: micropython-wasm 0.1a0 Hackers Simply Asked Meta AI to Give Them Access to High-Profile Instagram Accounts. It Worked May 2026 newsletter Release: datasette 1.0a32 The solution might be cancelling my AI subscription A quote from Karen Kwok for Reuters Breakingviews How we contain Claude across products Research: Running Python ASGI apps in the browser via Pyodide + a service worker I Am Retiring from Tech to Live Offline A quote from Daniel Jalkut Release: datasette 1.0a31 Anthropic's run-rate revenue hits $47 billion Claude Opus 4.8: “a modest but tangible improvement” Release: llm-anthropic 0.25.1 Tool: markdown-svg-renderer sqlite AGENTS.md I think Anthropic and OpenAI have found product-market fit A quote from Kyle Ferrana The pressure Microsoft Copilot Cowork Exfiltrates Files A quote from Paul Graham A quote from Corey Quinn Notes on Pope Leo XIV’s encyclical on AI Sighting: California Brown Pelican, Snowy Egret, California Sea Lion, Harbor Seal Release: datasette 1.0a30 Release: datasette-agent 0.1a4 Release: datasette-fixtures 0.1a0 A quote from Armin Ronacher Tool: Mad House — Usborne Creepy Computer Games On the <dl> Research: pydantic-monty investigation The memory shortage is causing a repricing of consumer electronics FTC to Require Cox Media Group, Two Other Firms to Pay Nearly $1 Million to Settle Charges They Deceived Customers About “Active Listening” AI-Powered Marketing Service Datasette Agent Release: datasette-agent-sprites 0.1a0 Release: datasette-agent-charts 0.1a2 Release: datasette-agent 0.1a3 A quote from SpaceX S-1 How fast is 10 tokens per second really? Google I/O, Gemini Spark, Antigravity Release: datasette-agent-charts 0.1a1 Release: llm-gemini 0.32 Gemini 3.5 Flash: more expensive, but Google plan to use it for everything Release: datasette-llm-accountant 0.1a4 Release: llm-gemini 0.32a0 Release: datasette-llm 0.1a8 Sighting: Glaucous-winged Gull, Brown Pelican, Snowy Egret, Canada Goose GDS weighs in on the NHS’s decision to retreat from Open Source Warelay -> OpenClaw A quote from Julia Evans Release: inaturalist-clumper 0.1 Sighting: Western Gull, Feral Pigeon Tool: QR code generator Release: datasette-llm-limits 0.1a0 Release: datasette-agent 0.1a2 Not so locked in any more Release: datasette-agent 0.1a1 Release: datasette-ip-rate-limit 0.1a0 Welcome to the Datasette blog A quote from Boris Mann Tool: CSP Allow-list Experiment Release: datasette 1.0a29 A quote from Mo Bitar Release: llm 0.32a2 Thoughts on GitLab’s workforce reduction A quote from James Shore Your AI Use Is Breaking My Brain TIL: Using LLM in the shebang line of a script Learning on the Shop floor A quote from New York Times Editors’ Note A quote from Andrew Quinn A quote from Luke Curley
Claude Fable is relentlessly proactive
Simon Willison · 2026-06-12 · via Simon Willison's Weblog

11th June 2026

After two days of experience with Claude Fable 5 I think the best way to describe it is relentlessly proactive. It knows a whole lot of tricks and it will deploy pretty much any of them to get to its goal.

I’ll illustrate this with an example. I was hacking on Datasette Agent today when I noticed a glitch: a horizontal scrollbar that shouldn’t be there in the jump menu chat prompt. I snapped this screenshot:

Screenshot of a modal dialog demonstrating a scrollbar bug. At the top is a focused search input with blue outline and placeholder "Jump to...", with an X close button to its right. Below, a heading reads "Start a new agent chat" above a textarea with the placeholder "Ask a question about your data..." — the bug: a thick gray horizontal scrollbar is incorrectly displayed along the bottom edge of the empty textarea, spanning nearly its full width, next to the resize handle. Below the textarea: "Press Enter to start. Shift+Enter adds a new line." followed by a blue "Start chat" button.

Then I started a fresh claude session in my datasette-agent checkout, dragged in the screenshot and told it:

Look at dependencies to help figure out why there is a horizontal scrollbar here

I had a hunch the cause was in a dependency of Datasette Agent (likely Datasette itself) and I knew Fable was good at digging into dependency code, either by inspecting installed files in its own virtual environment site-packages or by referencing a local checkout on disk. Telling it to start with dependencies felt like a good bet.

I got distracted by a domestic task and wandered away from my computer.

When I came back a few minutes later I saw my machine open a browser window in my regular Firefox and then navigate to the dialog in question. I had not told Claude Code to use any browser automation, and I was pretty sure it wasn’t possible for it to trigger mouse movements or keyboard shortcuts within a window, so how was it doing that?

I watched in fascination as it continued with its explorations, then saw it open a Safari window instead of Firefox. I also grabbed this snapshot from the Claude terminal:

Screenshot of two Bash tool calls in a dark terminal interface. First: Bash(open -a Safari /tmp/textarea-scrollbar-test.html && sleep 4 && uv run --with pyobjc-framework-Quartz python - <<'EOF' import Quartz wins = Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListOptionOnScreenOnly, Quartz.kCGNullWindowID) for w in wins: if (w.get('kCGWindowOwnerName') or '') == 'Safari' and 'textarea' in (w.get('kCGWindowName') or '').lower(): print(w.get('kCGWindowNumber')) EOF) with output 153551. Second: Bash(screencapture -x -o -l 153551 /tmp/safari-cases.png && echo ok) with output ok.

What was it doing there with uv run --with pyobjc-framework-Quartz?

It turns out Fable had hacked up its own pattern for taking screenshots of browser windows. It was using Python to iterate through all available windows on my machine, then filtering for Safari windows with expected strings such as "textarea" in the window name. It used that to find their window number—an integer like 153551—which it could then use with the screencapture CLI tool to grab a PNG.

OK fine, that’s a neat way of taking screenshots. But what was it taking screenshots of?

Turns out it had been writing its own scratch HTML pages to try and recreate the bug, then opening Safari and grabbing screenshots.

Here’s that /tmp/textarea-scrollbar-test.html page it created, and the screenshot it took with screencapture -x -o -l 153551 /tmp/safari-cases.png:

Screenshot of a Safari browser window showing a textarea scrollbar test page at file:///private/tmp/textarea-scrollbar-test.html. Page text reads: scrollbar thickness: 17px | UA: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.4 Safari/605.1.15 | devicePixelRatio: 2. Four numbered test cases follow, each with a textarea containing the placeholder "Ask a question about your data...": 1. Exact plugin CSS (resize: vertical, default overflow), 2. Plugin CSS + overflow-x: hidden, 3. Plugin CSS + resize: none, and 4. Bare default textarea, which is a much smaller box with the placeholder wrapping onto two lines. (I have way too many open tabs!)

OK, so I can see how it’s opening test pages and taking screenshots, but how on earth was it triggering the modal dialog that was meant to be under test? That’s only available via a click or a keyboard shortcut, and I couldn’t see a mechanism for it to run those in Safari.

I eventually figured out what it had done.

Claude was running in a folder that contained the source code for the application. It knows enough about Datasette to be able to run a local development server. It turns out it was editing Datasette’s own templates to add JavaScript that would trigger the correct keyboard shortcut as soon as the window opened, adding code like this:

<script>
window.addEventListener("load", function () {
  setTimeout(function () {
    document.dispatchEvent(new KeyboardEvent("keydown", {key: "/", bubbles: true}));
  }, 1200);
});
</script>

1.2 seconds after the window opens, this code triggers a simulated / key, which is the keyboard shortcut for opening the modal dialog.

There was one challenge left. In order to understand what was going on, Claude needed to run JavaScript on the page to take measurements for itself.

It wrote its own custom web application to capture information via CORS, then ran that as a local server and opened a page with JavaScript that would POST directly to it!

Here’s the Python web app it wrote, using the standard library http.server package:

from http.server import HTTPServer, BaseHTTPRequestHandler

class H(BaseHTTPRequestHandler):
    def do_POST(self):
        n = int(self.headers.get("Content-Length", 0))
        open("/tmp/diag.json", "w").write(self.rfile.read(n).decode())
        self.send_response(200)
        self.send_header("Access-Control-Allow-Origin", "*")
        self.end_headers()
    def do_OPTIONS(self):
        self.send_response(200)
        self.send_header("Access-Control-Allow-Origin", "*")
        self.send_header("Access-Control-Allow-Headers", "*")
        self.end_headers()
    def log_message(self, *a):  # quiet
        pass

HTTPServer(("127.0.0.1", 9999), H).serve_forever()

All this does is accept a POST request full of JSON and write that to the /tmp/diag.json file. It sends Access-Control-Allow-Origin: * headers (including from OPTIONS requests) so that code running on another domain can still communicate back to it.

Then Claude injected this code into the template that it was loading in a browser:

const host = document.querySelector("navigation-search");
const ta   = host.shadowRoot.querySelector("textarea");
const cs   = getComputedStyle(ta);
fetch("http://127.0.0.1:9999/diag", {
  method: "POST",
  body: JSON.stringify({
    dpr: window.devicePixelRatio,
    scrollWidth: ta.scrollWidth, clientWidth: ta.clientWidth,
    whiteSpace: cs.whiteSpace, width: cs.width,
  }),
});

This took measurements of the <textarea> inside the <navigation-search> Web Component and sent them to the server, which wrote them to a file on disk, which Claude could then read.

Having figured out all of these tricks Fable... hit some invisible guardrail and downgraded itself to Opus. Thankfully Opus had access to the full transcript and could continue using the tricks pioneered by Fable, and shortly afterwards found, tested and verified the fix.

I prompted Opus to:

Write a report in /tmp/automation-report.md where you note down all of the tricks you have used in this session to test against real browsers on my computer, include runnable code examples

Which produced this report, which was invaluable for piecing together the details of what had happened for this post.

I’ve shared the full terminal transcript of the Claude Code session as well.

A review of everything it did

Based on a screenshot and a one-line prompt, Claude Fable 5 + Claude Code:

  • Figured out the recipe to run the local development server (with fake environment variables needed to get it running)
  • Fired up a Playwright Chrome session
  • Turned on the visible scrollbars setting for Chrome defaults write com.google.chrome.for.testing AppleShowScrollBars Always (it turned that off again later)
  • Cycled through Firefox and WebKit in Playwright too, failing to recreate the bug
  • Worked out my default browser was Safari
  • Built a textarea-scrollbar-test.html HTML document
  • Opened that in real (not Playwright) Firefox
  • Found that osascript -e 'tell application "System Events" to tell process "firefox" to id of window 1' was blocked because “osascript is not allowed assistive access”
  • Figured out that uv run --with pyobjc-framework-Quartz python workaround, described above
  • Added JavaScript to the site templates in order to trigger the / key
  • Built its own little Python CORS web server to capture JSON data
  • Rewrote the template to capture that data and send it to the server
  • Scripted its way through the Web Component shadow DOM to the information it needed
  • Opened Safari to confirm the source of the bug
  • Modified its custom template to hack in a potential fix
  • Confirmed the hacked fix worked
  • Reported back on how to fix the problem

Like I said, relentlessly proactive!

An estimate of the cost

I’m currently on the $100/month Claude Max plan, which includes a generous allowance for Fable up until June 22nd after which Anthropic say they’ll start charging full API prices for it.

I’m using AgentsView to track my spending (see this TIL). Here’s what AgentsView says this session would have cost me if I was paying full price for it:

~ % uvx agentsview session usage be8850a7-6119-46a0-b5d6-79c7fff5ae2b
Session:       be8850a7-6119-46a0-b5d6-79c7fff5ae2b
Agent:         claude
Output:        68606
Peak ctx:      113178
Cost:          ~$12.11 (claude-fable-5, claude-opus-4-8)

If you don’t keep a close eye on it, Fable will quite happily burn $12 in tokens inventing new ways to debug your CSS.

I really need to lock this thing down

On the one hand, watching Fable go to extreme lengths to get the information that it needed to debug what was, in the end, a two-line CSS fix, was fascinating.

But on the other hand... this is a robust reminder that coding agents can do anything you can do by typing commands into a terminal—and frontier models know every trick in the book, and evidently a few that nobody has ever written down before.

If Fable had been acting on malicious instructions—a prompt injection attack hidden in code or an issue thread, or something I’d carelessly pasted into my terminal—it’s alarming to think quite how far it could go to exfiltrate data or cause other forms of mischief.

Running coding agents outside of a sandbox has always been a bad idea—it’s my top contender for a Challenger disaster incident, as described by Johann Rehberger in The Normalization of Deviance in AI.

Fable is arguably smarter and hence more suspicious of potentially malicious instructions. But that smartness is very much a two-edged sword: if it does get subverted by instructions, the amount of damage it can do given its relentless proactivity is terrifying.