Intercepting Claude Code CLI for Fun and More Fun

(this document is currently a draft)

I was working with Claude Code CLI this week, and I was having some connection issues that were preventing it from working. I broke out some of the old standard tools to diagnose the problem, including tcpdump and mitmproxy. Turns out the connection issue was something simple and easily corrected. (Claude Code CLI is a very useful tool by the way, works great as long as you aren't tinkering with your lab network in a way that inadvertently prevents it from connecting to its servers.) Since I already had it set up, I decided to take a peek at what Claude was doing behind the scenes using the mitmproxy logs. Spoilers, it's nothing Earth-shattering, but it's still kind of interesting, to me anyway. Take a look.

First I set up mitmproxy. I haven't used it in a while, but it was nice to see its development has continued. I generated a cert as instructed, and then fired it up in a terminal. I might be able to use the NODE_TLS_REJECT_UNAUTHORIZED environment variable to skip this step, but for now, I decided to just do things the "right" way.

Then I kicked off Claude Code CLI, giving it the necessary directions to use the proxy and its certificate.

And right off the bat, you can see the client is dialing up several servers before I've asked it to do anything. The call to googleapis.com is just a version check. The calls to github appear to be looking at official plugins. Not sure why the one call got a cert error when all the other ones didn't, but I'll circle back to this github activity later.

Looks like basic telemetry and usage is being sent to datadoghq.com. I took a glance at the payload, and I don't see anything I personally object to being collected here. It does reveal that I'm using kitty term, but other than that, there's nothing specific to me or how I'm using the software. It's possible this could even be disabled, and it could certainly be blocked, but I'm not terribly worried about it.

Alright, let's send it a simple test prompt and see what happens.

More stuff to look at. A lot more stuff than I was expecting to be honest. A "hello" call to the API for my hello? Coincidence I think, it looks like a simple check to make sure the server is available and responding. You can also see I'm using OpenRouter.ai, which is a convenient service with a few nice bells and whistles I use. If you see my API token in there, rest assured it's one I created for this post, and deleted afterward. So don't bother trying to use it, unless you really want to, in which case go for it. (And if you somehow do find something exploitable in there I've missed, be a pal and let me know!)

The next flow is where things get more interesting. There's my prompt. And the response is in this payload as well. You can immediately see that Claude Code CLI is using Anthropic's own SDK and its JSON-formatted API, which makes perfect sense: https://platform.claude.com/docs/en/api/client-sdks

Let's take a closer look at this request. You can see in the "messages" element my exact request, along with some basic instructions on how to handle it. The "system" element contains considerably more content. Here's just one system prompt, too long to post right in this article Claude Code CLI System Prompt (Note, there were some '<' characters in there that broke my markdown formatting, so I manually inserted a few backslash escapes to fix it.)

So, if you've spent a good deal of time working in security, you're already thinking the same thing I am. Can I get this tool to do something it shouldn't by manipulating these requests on the fly? Before I even go there, I'll say my gut is already telling me "no". Like I said, they're just using their own TypeScript SDK, so anything I could do by changing the raw API requests should also be possible using their SDK. Nonetheless, if nobody ever tried, we'd never find these sorts of problems when they do exist in the wild.

So (after I take a peek at Anthropic's ToS, last thing I'd want to do is get myself banned from the service) I'll dive a bit deeper into this effort. Stay tuned for Part 2.