Lab Solved — Exploiting Vulnerabilities in LLM APIs
- LLM Security
- Pentesting
- AI Security
- OS Command Injection
On this page
LLM Pentesting Series — Part 3
This walkthrough is intended only for PortSwigger’s authorized Web Security Academy environment. Do not test these techniques against systems without permission.
Introduction
In Part 3 of the LLM Pentesting series, we will solve PortSwigger’s “Exploiting vulnerabilities in LLM APIs” lab.
The lab demonstrates how an attacker can abuse an LLM’s API integrations to attack the underlying system. This time, we will perform OS command injection through a vulnerable LLM API.
The objective is to delete the morale.txt file from Carlos’s home directory.
Lab Architecture
The high-level architecture is shown in Figure 1.

The diagram uses colors and numbered steps along the red path. Here is what they mean:
- Red path: The path the attacker takes.
- Yellow path: Controls that would stop the attack if they were implemented, or implemented correctly.
- Numbers on the red path: The steps the attacker follows to exploit the endpoint. We will use these numbers while explaining the exploit.
How to Exploit
Step 1: Find the LLM Interaction Page
First, locate any page on the site that integrates the LLM.

As shown in Figure 2, the site has a live chat feature. This is our entry point for the exploitation.
Steps 2–3: Interact with the Model and Enumerate Its Functions

In Figure 3, we start interacting with the model. Notice that it behaves strangely in response to the first question. Keep this in mind, because the same behavior appears again during the OS command injection attempts.
Steps 4–8: Focus on the Newsletter Subscription
There are several steps here, but the key point is that I interacted with the LLM extensively to identify which endpoint was exploitable, trying different approaches along the way.
Eventually, I realized that the newsletter subscription function was a good candidate for injecting commands into the server side.

After some trial and error, we learn that the function is called newsletter_subscription and that it takes an email address as input. Internally, it works something like this:
newsletter_subscription(String email) -> String:
system.run("sendemail {email}")Can you see the issue? It calls another service through the command line. That gives us an opportunity.
Steps 9–12: Exploit the System
In the architecture diagram these are separate steps, but for this walkthrough we can treat them as one.

Can you see the problem? The model takes our “$(whoami)” payload and rewrites it as ‘assistant’ or ‘customer’. Have a look at Figure 5 to see what I mean. After several attempts, I managed to execute “$(whoami)” directly inside the email command.

Now we can see that the server side is running as carlos. Next, we can try something like “$(ls)”.

It reports success. We will confirm the result in Figure 8.

As you can see, morale.txt is right in front of us. Now we can run “$(rm morale.txt)”.

The function returns an error. Why? Because it then tries to send an email to an invalid address. But by that point, the injected command has already executed.
morale.txt is deleted, and the lab is solved.
Conclusion
This was one of the most interesting labs I have solved so far. It is a strange combination of a classic vulnerability and a new technology integrated into a system, and together they create a dangerous attack path.
We will keep going deeper down the rabbit hole. There is much more to explore.
I hope this was helpful and gave you a different perspective on the attack surface of 2026.
See you in the next lab!
References
- If you want to solve it yourself: PortSwigger — Exploiting vulnerabilities in LLM APIs lab
- If you prefer watching over reading: YouTube walkthrough
- Part 2: Lab Solved — Indirect Prompt Injection