On this page
  1. The attack surface your LLM feature adds
  2. Prompt injection: When untrusted text becomes an instruction
  3. The lethal trifecta: The configuration that turns injection into a breach
  4. MCP servers: How agents get tools, and how they get exploited
  5. Non-human identities: The accounts your agent acts as
  6. Secrets and credentials in agent-assisted code
  7. Hallucinated packages and the AI supply chain
  8. Agent-specific tests and red-teaming: Finding these before an attacker does
  9. Checklist
  10. FAQ
    1. What’s the difference between securing an AI agent and securing a normal web app?
    2. Is prompt injection actually exploitable, or is it a theoretical risk?
    3. Do I need to secure an MCP server that only runs on my laptop?
    4. Where should I start if my app already has an LLM feature?
  11. Related topics
  12. Sources
guide

Securing AI Agents and LLM Features: The Attack Surface You Just Added

Prompt injection, MCP servers, non-human identities, and hallucinated packages — every security concept that applies once your app has an LLM feature or an AI agent. With linked guides.

Quick answer

  • An LLM feature removes the line between instructions and data. Any text the model reads is text it may act on, including text an attacker wrote.
  • Prompt injection is the root pattern; the “lethal trifecta” (private data + untrusted content + outbound access) is the configuration that makes it dangerous.
  • Agents act through tools and credentials, so most real damage comes from over-scoped permissions rather than a clever prompt. Scope tool access to the task.
  • MCP servers are the standard way agents get tools. Treat each one as a service account with a defined, minimal set of rights.
  • Verify every package your assistant adds — hallucinated names are a live supply-chain attack.
  • Every concept below links to a full guide. Start with permissions and prompt injection, then work down.

The attack surface your LLM feature adds

Adding a model call to an app is not like adding a library. It introduces a component that reads untrusted text and produces actions, which means the traditional question — “did this input come from a trusted source?” — becomes hard to answer. The model cannot reliably tell a customer’s note from your own instructions, because both arrive as plain text in the same context.

The consequence is a security model that looks inverted next to a normal web app. Instead of filtering input and validating output, you have to assume the model’s output is advisory and enforce every restriction in the code around it: what the agent may call, with which credentials, on whose behalf, and with what confirmation.

The guides below cover that surface in the order it becomes relevant: the injection pattern first, then the access and identity questions, then the supply chain, then how to test any of it.


Prompt injection: When untrusted text becomes an instruction

Prompt injection is the web’s oldest vulnerability class applied to a new input: instead of sending SQL to a database, the attacker sends instructions to a model. It has two shapes — direct (a user types “ignore your rules”) and indirect (a document, ticket, review, or web page the agent retrieves contains the instruction). Indirect is the one that catches builders off guard, because the attacker never touches your app directly.


The lethal trifecta: The configuration that turns injection into a breach

Three properties together make an agent dangerous: it can read private data, it processes untrusted content, and it can communicate outward. Remove any one and the injection has nowhere to go. That framing is more useful than trying to sanitize prompt text, because it’s a property of your architecture rather than of the attacker’s payload.


MCP servers: How agents get tools, and how they get exploited

The Model Context Protocol lets an agent discover and call external tools — a filesystem, a database, a ticket tracker, a browser. That convenience is also a permission grant. An MCP server that runs with standing credentials turns a prompt injection into a real action performed with your identity, and the protocol’s early implementations assume a level of trust between client and server that most deployments don’t actually verify.


Non-human identities: The accounts your agent acts as

Every tool call happens as somebody. Service accounts, API keys, OAuth clients, and agent tokens are non-human identities, and AI-assisted environments create them faster than they get retired — one per integration, one per agent, often with broad scopes because narrowing them takes time. The result is a population of credentials that no human logs into, nobody rotates, and almost nobody audits.


Secrets and credentials in agent-assisted code

An assistant writing your code also writes your configuration, and it does so with no convention unless you gave it one. That’s why agent-generated projects produce the same three problems repeatedly: credentials inline in source, .env files committed to Git, and secrets pasted straight into a chat prompt where they live in a provider’s logs.


Hallucinated packages and the AI supply chain

Language models generate plausible names. Occasionally a plausible name is also the name of a real package that an attacker registered in anticipation — that’s slopsquatting, and it turns a typo-squatting trick into something a model can trigger on your behalf. The mitigation is unglamorous: verify the package exists, that it’s the one you meant, and that its download and maintainer history make sense before you install it.


Agent-specific tests and red-teaming: Finding these before an attacker does

None of the above is caught by a linter. Prompt injection needs a test that feeds hostile text through the real pipeline, agent permissions need a review of what each tool can reach, and secrets need a scanner running on every commit. Static analysis and dependency scanning cover the older failure classes that still ship alongside the new ones.


Where this bites vibecoders

The characteristic failure isn’t a jailbreak — it’s an agent with more permission than the feature needed. An assistant asked to “add an AI assistant to my app” reaches for a pattern that looks like the documentation: a broad API key in the environment, tools wired up without scopes, retrieved content passed straight into the same context as the system prompt, and no confirmation step before writes. Each choice is reasonable in isolation and invisible in review, because the code that results looks exactly like working code. Then a customer pastes text into a field the agent reads, and the tool call that follows is one your app authorized with a token that could do far more than the task required. Reviewing the permissions — not the prompt — is what catches it.

Checklist

  • Inventory every tool your agent can call and what credential each one uses.
  • Delete every permission the current task doesn’t need; add them back when required.
  • Put human confirmation in front of writes, sends, payments, and deletions.
  • Keep private data, untrusted content, and outbound access out of the same agent whenever you can.
  • Treat every MCP server as a service account: scope it, log it, rotate it.
  • Scan for hardcoded secrets on every commit, not on a schedule.
  • Verify package names and maintainers before installing anything an assistant suggests.
  • Rotate any credential that has ever been pasted into a prompt or an agent’s context.
  • Test the injection path with hostile input instead of assuming filtering handles it.

FAQ

What’s the difference between securing an AI agent and securing a normal web app?

A normal web app separates code from data. An LLM feature does not — user content, retrieved documents, and system instructions all arrive as the same kind of text, so any text the model reads is a potential instruction. That means the classic boundary — “is this input trusted?” — no longer maps cleanly onto the request, and you have to enforce permissions in code outside the model.

Is prompt injection actually exploitable, or is it a theoretical risk?

It is exploitable whenever untrusted text reaches a model that can cause an effect — calling a tool, writing to a database, sending a message, or returning content the user trusts. The exploit is often mundane: a support ticket, a web page, or a PDF contains instructions that redirect what the agent does next. The severity depends on the agent’s permissions, which is why scoping them matters more than filtering prompts.

Do I need to secure an MCP server that only runs on my laptop?

Yes, if it holds real credentials. A local MCP server typically runs with standing access to your files, your repositories, or your accounts, and any content the model reads can trigger it. The realistic risk is not a remote attacker — it’s a tool call your agent shouldn’t have made, made with a token that had more scope than the task needed.

Where should I start if my app already has an LLM feature?

Inventory the agent’s permissions first: what tools it can call, what credentials those tools use, and what data they can read or write. Then remove every permission the feature doesn’t need, and put human confirmation in front of the destructive ones. That single pass prevents more real incidents than any prompt-level filtering.


Sources

Share: