Agent pasted a “captcha” into Terminal. It lived on my Mac for 30 days.

· Medium ·

3 min read Original article ↗

gvs chaitanya

On August 9 I hit a page that said I was a bot. Prove you’re human.The agent took control of the machine and pasted the code in Terminal

That was the whole attack. No exploit. No zero day. It ran it.

Press enter or click to view image in full size

What I thought happened

A few days later someone was inside my LinkedIn. I caught it fast, kicked them out, changed the password. Then I changed every other password. Killed every process I didn’t recognise. Told myself it was handled.

It was not handled.

How I actually found it

September 6. I was setting up an unrelated open source tool and had Claude Code check what was running on the machine. In the process list, this:

Press enter or click to view image in full size

Curl to a random domain, output piped straight into osascript. Running since the day before. Parent process started at login.

What it was

A LaunchAgent at ~/Library/LaunchAgents/com.qxgpjsivitldyooj.plist, created 21:20 on August 9. Two flags: RunAtLoad and KeepAlive. It starts at every login. If you kill it, macOS restarts it. That is why “I killed everything” did nothing.

Press enter or click to view image in full size

Inside the plist: a base64 blob. Decode it and you get AppleScript where every string is built one character at a time. (ASCII character 112) & (ASCII character 111) & … Hundreds of those. Built to survive a grep.

Decoded, it does this:

  1. Calls four Polygon blockchain RPC nodes: polygon.drpc.org, polygon.publicnode.com, polygon-mainnet.gateway.tatum.io, tenderly.rpc.polygon.community.

2. Sends an eth_call to contract 0xA3a603F8a454a9c905b4c579Bb72628F7C15C2A0.

3. Reads the hex that comes back and decodes it into a domain. That day the domain was d9mjs.sbs.

4. POSTs to that domain with my tracking id and pipes whatever comes back into osascript.

The command server address is not in the script. It is on a blockchain. Nobody can take it down, and the operator can change it with one transaction. The technique has a name: EtherHiding.

Whatever the server sends runs as me, with my password sitting in ~/.passphrase where the first stage saved it. Keychain, browser passwords, cookies, wallets, SSH keys, API keys. There was a staging folder, ~/tempFolderC, already empty. Upload done.

The LinkedIn break-in was a stolen session cookie. They never needed the password.

What actually fixed it

Not the password changes. Those happened while the agent was still running.

launchctl bootout gui/$(id -u)/com.qxgpjsivitldyooj

rm ~/Library/LaunchAgents/com.qxgpjsivitldyooj.plist

Kill the process tree. Delete .passphrase, .txid, tempFolderC. Reboot. Check again.

Then the part people skip:

1. Sign out of all sessions everywhere. Google, GitHub, Slack, Notion, LinkedIn. 2FA does not help while a stolen cookie is still valid.

2. 2FA on every login.

3. Regenerate API keys and SSH keys. They have no 2FA.

4. Do all of it from a different device.

Close the tab.” then “As long as you are connected to the internet, you are not safe.”