Back to Index

Case study · Applied AI · Tooling

magneto-browse

A browser-automation agent that lets an AI model read and operate real websites through a compact, structured view of the page, with a credential vault that logs in on the model's behalf so passwords never pass through it.

RoleSole engineer
Timeline2026, ongoing
StackNode.js · Model Context Protocol · Chrome extension (TypeScript) · Swift / WKWebView
StatusIn daily use by my agent fleet

The problem

Language models are good at deciding what to do on a web page and bad at seeing one. Raw HTML is too large and too noisy; screenshots are expensive and lossy for text. And the moment an agent needs to log in somewhere, you face a choice between giving the model a password and not logging in. I wanted a tool that solved both: a small, faithful view of the page, and a way to authenticate that keeps secrets out of the model's context entirely.

My role

Everything: the protocol, the server, both browser back ends, the vault, the tests, and the operational hardening that followed a security finding in my own code.

What I built

Architecture

Model clientMCP over HTTP Node MCP servertools · digest · difforigin gate · audit log Vault (local, by origin) Chrome extensionDOM executor · aria tree Native macOS (WKWebView)trusted CGEvent input Same WebSocket protocol, either back end.

magneto-browse architecture: model client to MCP server to a WebSocket bridge with two interchangeable browser back ends; the vault sits beside the server and injects credentials directly into the browser.

Difficult problems

The bug I found in my own tool. An audit turned up a cross-site WebSocket hijacking flaw: the local bridge accepted connections without validating the Origin header, so any web page could have connected and, one hop later, reached the vault. Fixed with strict origin validation and per-role tokens. It also became the thesis for a bug-bounty focus on local services and desktop attack surfaces, because that is the class of bug building this tool taught me to look for.

Time-of-check versus time-of-use on login. The vault looks up a credential by origin, but the page can navigate between lookup and typing. The native client re-checks the live origin immediately before typing and fails closed.

// vault login returns only facts about what happened, never the secret
{ "username_filled": true, "password_filled": true, "submitted": true, "final_origin": "https://github.com" }

Hidden file inputs. Upload widgets like Gmail's hide the real input element. A visibility gate that was right for buttons was wrong for file inputs; the check now asks "is this a file input that is enabled" rather than "can a human see it."

Widgets that check isTrusted. Some sites ignore synthetic clicks. The extension cannot fix that; the native back end can, by generating hardware-level events. That asymmetry is why there are two back ends.

Decisions and tradeoffs

Impact

2interchangeable browser back ends, one protocol
0passwords in model context or logs
1high-severity flaw found and fixed before it could be used
Previous: ADUAtlasBack to Index
Download PDF