Welcome back, aspiring cyberwarriors!
In our previous article, we discussed the importance of securing your AI supply chain and introduced the Router-in-the-Middle (RITM) attack. Now it’s time to create a Python script that demonstrates this attack using FastAPI and OpenRouter.
In this article, we’re focusing on AC-2, a passive secret exfiltration technique. Before we dive into the code, it’s important to mention that everything we’re doing here is for educational purposes only.
The goal is to build a Python script that works as an LLM API router, sitting between a client, such as your code or any AI-compatible agent, and the real upstream provider, OpenRouter. The script will terminate the client’s TLS connection and establish a new one to OpenRouter. This setup allows it to access both the incoming requests and outgoing responses in plaintext. While it forwards these requests and responses exactly as they are, it will also quietly scan the traffic for any secrets and log them without anyone noticing. This means both the client and OpenRouter will see everything as perfectly normal.
Let’s get rolling!
Step #1: Preparation
Before we begin scripting, it’s important to set up a Python virtual environment and install a few dependencies.
kali> mkdir ~/ac2-demo && cd ~/ac2-demo
kali> python3 -m venv venv
kali> source venv/bin/activate
kali> pip3 install fastapi uvicorn requests pydantic

FastAPI and uvicorn create a lightweight, async-compatible HTTP server that looks like a normal OpenAI-compatible endpoint. Requests are used to talk to other services by sending HTTP requests. And Pydantic ensures that incoming and outgoing data match expected types and structures, helping prevent errors.
Step #2: Getting Started with Writing the Code
First, we need to create a Python file and open it with your preferred text editor; in this case, I’ll be using Sublime Text. Feel free to use whichever editor you like.
At the beginning of the script, we typically include a shebang line to specify that we want to run the script with the Python interpreter. Following that, we will add a few import statements, as shown below:

We have already mentioned most of the items during installation. The only concepts that require further explanation are ‘re’, which is used for regex-based secret detection, and ‘asyncio’, which enables non-blocking logging of secrets to prevent exfiltration from delaying the response.
Next, we need to create a web application instance using the FastAPI framework and set up configurations such as the upstream URL, a valid OpenRouter API key, and others.

Looks good. Now let’s specify the items we want to extract, such as AWS keys or PEM keys.

Step #3: Defining the Core Functions
First, let’s define a simple function that scans any strings for secrets and returns output without duplicates.

Next, let’s define an asynchronous function named log_exfil that prints the found secrets and saves them to a file.

Another important aspect is declaring multiple decorators so that our router can catch requests to /v1/chat/completions (standard behavior) and also handle requests to /chat/completions (a common mistake by simplified clients).

Let’s write the main code that will receive and scan the request.

In the code above, we read the raw request body from the client, which is in JSON format. We combine the headers and the body into a single string, then run the `extract_secrets()` function. If any credentials are detected (for example, if you accidentally include an AWS key in a prompt), they are immediately logged. However, the original `body_bytes` remains untouched.
Next, the request is forwarded exactly as the client sent it, except that the Authorization header is replaced with the router’s key. OpenRouter processes it as a normal request. We scan the response passively and stream it back.

The response is sent back to the client in chunks, unmodified. Only after the entire response has been collected and while it remains hidden from the client does the system run the `extract_secrets()` function on the response body. This process enables the identification of any secrets that may appear in the results of tool calls or model outputs.

Finally, write code to start our router on the previously defined port. Any client setting its base URL to http://your-kali:port will pass through this AC-2 proxy.
Step #4: Run the AC-2 Proxy
To run it, use the following command:
kali> python3 HackersArise_router_ac2.py

Keep this terminal running.
To test the script, we can use any client compatible with OpenAI or simply use curl. I have prepared the following request for our proxy:
curl -X POST http://localhost:4444/v1/chat/completions \
-H "Authorization: Bearer dummy-router-key" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-4o-mini",
"messages": [
{"role": "user", "content": "Here is my secret AWS key for testing: AKIAIOSFODNN7EXAMPLE1234567"}
]}'
Although the AI agent responded that it can’t help with sensitive information, our proxy captured the AWS key.

If we continue communicating with OpenRouter and enter the sensitive data, our proxy will alert us.

In addition to the prompts displayed in the terminal, we have a file called exfiltrated_secrets.log that records all findings.

Summary
In this article, we created a Python script to demonstrate a Router-in-the-Middle (RITM) attack. Our router acts as a proxy, which means it terminates the client’s TLS connection and establishes a new one to the model provider. This way, it can see all the request and response data without having to mess around with MITM techniques.
If you want to enhance your Python skills and feel confident in creating your own hacking tools, consider our course, Python Basics for Hackers, 3rd Edition. It includes 21 lessons and 7.5 hours of video content.
Source: HackersArise
Source Link: https://hackers-arise.com/artificial-intelligence-ai-in-cybersecurity-targeting-llm-supply-chains-with-router-in-the-middle-attacks/