

An interactive playground for LLM security testing
TLDR: I spent Day 3 working through Tom Abai's interactive playground for the OWASP Top 10 for LLM applications. It gave me a broad tour of prompt injection, supply-chain attacks, data poisoning, insecure output handling, system-prompt leakage, RAG weaknesses, misinformation, and unbounded consumption. The important lesson was not a clever prompt. It was learning to follow untrusted model output into the next component.
I have been learning LLM security through PortSwigger's Web LLM attacks labs, which are focused and practical. For this session I wanted a wider view, so I tried Tom Abai's interactive LLM security playground alongside the OWASP Top 10 for LLMs and GenAI applications. Tom's site is also worth following as the source behind the playground.
The playground is organised as ten short sections, one for each OWASP risk. Some are genuine challenges. Others are demonstrations of what can go wrong. That distinction matters: a page showing a poisoned dataset can be useful, but it is not the same thing as giving the learner a clear objective, a test condition, and a success signal.

Prompt injection is social engineering for a model
Prompt injection was the first and most familiar topic. The basic attack is simple: provide instructions that alter the model's behaviour in a way the application did not intend. The interesting part is that the malicious instruction does not always come directly from the user. It can arrive inside a document, a web page, an email, a product review, or a retrieved chunk of data.
That is why I think of prompt injection as social engineering at the AI layer. The attacker is trying to make the model reinterpret who is giving it instructions and what the task really is. The problem becomes much more serious when the model has access to private data or tools that can act in the real world. OpenAI describes the same shape of attack as harmful instructions hidden in ordinary content that an agent encounters while doing a task. Their overview is a useful companion read: Understanding prompt injections.
This means that a model analysing a large body of text can be exposed even when the person using it has done nothing suspicious. A public chat, forum, blog, email, or document can carry an indirect prompt injection that is activated when a bot later reads and summarises it.

PortSwigger's illustration makes the attack path very clear. The user asks about shoes, the LLM reads an external review, and the review contains an instruction to delete the user's account. The model then calls an internal API and reports that the account was deleted. The user never supplied the malicious instruction directly.
This is a high-impact web application failure mode because modern assistants constantly ingest external content while searching, summarising, or participating in conversations. External content needs to be treated as untrusted before it enters the model, but sanitisation alone cannot reliably remove instructions hidden in natural language. There also need to be independent checks after the model responds, before that response can invoke a tool, expose credentials, or perform a destructive action.
That is the control boundary I want to remember:
external content → validation and isolation → LLM
↓
policy and authorisation checks
↓
tool or data sink
My practical takeaway is to separate three questions during testing:
- What did the user ask the model to do?
- What other content entered the model's context?
- What can the model do with the resulting answer?
The second question is where indirect prompt injection lives. The third is where impact is usually decided.
Supply chain and data poisoning move the attack earlier
The supply-chain section shifted my attention away from the chat interface. An LLM application depends on more than a model: it may depend on training data, fine-tuning data, embedding models, vector stores, plugins, libraries, and deployment artefacts. Any unverified component can become part of the attack surface.
Data poisoning is the clearest example. If training or embedding data is manipulated, the attacker may introduce bias, harmful behaviour, or a hidden trigger that activates a backdoor later. A model trained on an unrepresentative or deliberately toxic corpus can produce unsafe results even when the user prompt looks harmless.
The playground showed the progression clearly: a clean sentence can be changed into a toxic version, or an ordinary instruction can acquire a hidden trigger such as an administrative mode. The data may still look like a normal training set at a glance, which is why provenance and review matter.

The defensive ideas are familiar from ordinary software supply chains: validate data sources, monitor changes in model behaviour, verify checksums and signatures, pin dependencies, and make deployment reproducible. The hard part is that model behaviour is not as easy to diff as a binary. Testing needs to include known prompts and behavioural checks, not only package integrity.
Improper output handling is where the model meets the application
This was the most valuable section for me because it connected LLM security to standard application security. OWASP's description of improper output handling is straightforward: model output needs validation, sanitisation, and context-aware handling before it is passed downstream.
The model's answer should be treated as untrusted data. If it is inserted into HTML, the concern may be XSS. If it is used to build a SQL query, it may become SQL injection. If it is passed to a shell or interpreter, it may become command or code execution. If it constructs a file path, it may become path traversal.
The playground pointed to a real vulnerability rather than inventing a hypothetical calculator. The Snyk advisory for CVE-2023-29374 describes arbitrary code execution in affected LangChain versions, where an attacker could influence the expression sent to Python's eval().
The cleanest example in the playground was that LangChain calculator pattern using eval() and exec():
attacker-controlled input
↓
LLM
↓
Python expression generated as text
↓
eval/exec
↓
Python runtime, files, secrets, network

eval() and exec() are not automatically vulnerabilities. The dangerous pattern is allowing untrusted or attacker-influenced data to reach an interpreter as executable code. That is the same source-to-sink reasoning used for SQL injection and command injection, with the LLM acting as an indirect route.
OWASP's mitigations are the right baseline: use allowlists and structured outputs, validate before invoking backend functions, encode for the destination context, use parameterised queries, and apply least privilege.
A link can become an exfiltration channel
One of the most memorable examples came from Embrace The Red's article on trusting LLM responses. The article is published on wunderwuzzi's blog. A chatbot was tricked into putting a summary of its conversation into a hyperlink. A client application that automatically previewed or retrieved the URL then sent that data to an attacker-controlled server.

The model did not need a traditional network tool with an obvious send_data function. It only needed to produce a URL, and the surrounding application did the rest. The scenario was a bot participating in a public conversation, where links were automatically inspected. That makes the link an exfiltration channel.
This is a useful way to think about indirect prompt injection. A user can be talking in a public chat, forum, or blog space, while a bot quietly analyses the conversation. If an attacker leaves instructions in that public content, the bot may follow them later. The attack becomes much more dangerous when the bot is also allowed to read private context or retrieve content from an untrusted source.

The attack surface therefore includes client behaviour: Markdown rendering, link previews, image loading, browser extensions, and automatic URL fetching.
The system-prompt-leakage section made a related point. Leaking a system prompt is not always a catastrophic vulnerability by itself, but it can expose security controls, hidden tool names, architectural details, and assumptions that help with the next attack. A prompt is not a security boundary or a secret that can safely contain credentials.
RAG needs access control, not just retrieval quality
The vector and embedding section was particularly relevant because I have built RAG pipelines before. A typical system chunks documents, embeds them, stores vectors, retrieves the nearest matches, and gives those chunks to the model. But semantic similarity is not authorisation.

If a user is not allowed to read a document, retrieving it and placing it in the model's context before checking permissions is too late. The access boundary should be enforced during retrieval, or at the latest before context construction, using tenant, identity, department, or document-level permissions. Otherwise prompt injection or an apparently innocent question can turn retrieval into an access-control bypass.
The remaining risks are still worth knowing
Misinformation was less of a lab and more of a reminder that probabilistic systems can produce convincing falsehoods. It is not the same class of problem as remote code execution, but it matters when an application presents an answer as authoritative or uses it to make a decision.
Unbounded consumption was more concrete: send prompts that force long responses, repeated reasoning, or expensive processing until the system exhausts tokens, compute, or budget.

The attack is essentially denial of service with an LLM-specific cost model. Rate limits, maximum input and output sizes, timeouts, per-user budgets, cancellation, and monitoring are not optional polish when every request can incur inference cost.
My verdict: useful map, shallow destination
The playground helped me build a broad mental model quickly. It is a reasonable starting point for someone new to the OWASP risks, especially if they use it as a catalogue of questions to investigate. But several sections were too lightly specified to feel like proper labs. The objective was not always clear, and in some cases it was difficult to tell what had actually been solved.
For learning, I would use it in this order: skim the ten categories, read the relevant OWASP page, reproduce one or two attacks in a deliberately vulnerable local application, and then study a real incident or research write-up. The OWASP Top 10 is a better reference than the playground alone. Gandalf also looks like a more focused next step for practising prompt attacks directly.
The biggest change in my thinking is simple: do not stop when the model follows the malicious instruction. Trace the output. Ask what parses it, renders it, retrieves it, executes it, or sends it somewhere else. That downstream boundary is where a strange model response becomes a normal security vulnerability.
Takeaways
- Put authorisation at the tool and retrieval layers. The model is not a security boundary.
- Treat prompts, retrieved documents, and model responses as untrusted input.
- Test the complete path from attacker input to the final sink, including client-side behaviour.
- Use the playground as an overview, then reproduce selected attacks in a controlled lab and read the underlying research.
Filed under ai, llm, prompt-injection, application-security, red-teaming. If any of this is wrong, or you have hit the same thing, tell me.
Published 16 September 2026.