OWASP LLM Top 10 (2026) mapping
This page maps every item of the OWASP Top 10 for LLM Applications 2026 to the LiteLLM gateway controls that address it, says how each control is turned on, and states where each one stops. It is written for a security reviewer filling in a questionnaire and for the platform team deciding which controls to enable. Every claim on it was checked against the LiteLLM main branch at version 1.104.0 (September 2026); the last section says how to re-check it against the version you run
LiteLLM sits between your callers and the model providers, so its controls cover what the gateway can see: the request, the response, the tools and MCP servers it brokers, the files and vector stores it manages, and its own configuration, container image, and dependencies. What a provider's model does internally, and what your application does with a response after the gateway returns it, are out of its reach. Every item below therefore keeps a share that stays with the application or the provider, and each section names it
Each section has three parts: what ships, how to turn it on, and known limits. Nearly every control is off until you configure it, and the defaults quoted here are the code defaults on the version above. The table is the short version
| Item | Main gateway controls | Default state |
|---|---|---|
| LLM01 Prompt Injection | Input, tool, and MCP guardrails | Off |
| LLM02 Sensitive Information Disclosure | PII masking, secret detection, log redaction, encryption at rest | Off, except key hashing |
| LLM03 Excessive Agency | MCP, A2A, and tool permissions, route allowlists | Open until granted |
| LLM04 Supply Chain | Signed images, frozen lockfile, scanning CI, client api_base block | On |
| LLM05 Data and Model Poisoning | Upload limits, batch guardrails, admin-only writes | Mixed |
| LLM06 Unbounded Consumption | Budgets, rate limits, admission control, size caps | Off |
| LLM07 Misinformation | Grounding checks, judge guardrail, deprecation warnings | Off |
| LLM08 Hidden Context Exposure | Log redaction, server-side prompts, leak patterns | Off |
| LLM09 Vector and Embedding Weaknesses | Store access control, ingest checks | Mixed |
| LLM10 Improper Output Handling | Output guardrails, stream buffering, tool permission | Off |
LLM01 Prompt Injection​
The 2026 entry covers direct and indirect injection, including payloads carried in images and audio and instructions smuggled through tool results and MCP servers
What ships. The guardrails framework runs a guardrail before the provider call (pre_call), alongside it (during_call), or on the response (post_call). One guardrail definition covers the chat, text completion, Responses API, Anthropic Messages, Google GenAI, embeddings, image generation, speech, transcription, video, rerank, OCR, Bedrock pass-through, A2A, and MCP routes, because the framework translates each of those shapes into the text a guardrail scans. Over fifty guardrail integrations ship in the guardrail hooks directory, from the LiteLLM Content Filter, whose prebuilt patterns include prompt_injection_jailbreak, prompt_injection_system_prompt, prompt_injection_data_exfiltration, prompt_injection_malicious_code, and prompt_injection_sql, to the hosted detectors from Lakera, Prompt Security, Azure, Bedrock, and others. The older prompt injection detection callback adds a heuristic and an LLM check. System and tool messages are scanned along with user turns unless you set the skip flags. On the MCP side, MCP guardrails run on every tool call, tool filtering limits which tools a key can reach, and the tool permission guardrail and tool policies decide which function calls the model may make. For voice, realtime guardrails scan the input transcription of a Realtime session. For images, the Content Filter can describe an image with a vision model and filter the description
How to turn it on. Add the guardrail under guardrails: in config.yaml with mode: pre_call (or during_call when latency matters more than blocking), then either set default_on: true so it runs on every request or attach it to specific keys, teams, or requests. Nothing is scanned until a guardrail is defined; default_on is false
Known limits. Guardrails are classifiers, so a crafted injection can pass any of them. Treat them as one layer and pair them with the LLM03 controls, so a successful injection has little it can act on. The built-in detection callback runs only on completion, text completion, embeddings, image generation, moderation, and audio transcription calls, so /v1/messages and /v1/responses traffic skips it; use a guardrail with mode: pre_call for those routes. That callback also fails open on a non-HTTP error, logs the rejected input at INFO, and its vector similarity option is not implemented, so only its heuristic and LLM checks run. Cross-modal payloads are scanned only when you configure a guardrail that looks at them: the Content Filter's image description path is opt-in and costs a vision call per request, audio and file parts on chat requests and image parts on MCP calls go to the provider unscanned, and the Azure Prompt Shield integration sends the messages without attached documents. The tool descriptions an upstream MCP server returns are not scanned or pinned, so a server can change what a tool claims to do after you approved it (PR #43283 is in review for this). Only the Content Filter supports the realtime input transcription mode
LLM02 Sensitive Information Disclosure​
The entry covers PII, credentials, and proprietary data leaving through prompts, responses, logs, and caches
What ships. PII masking with Presidio masks or blocks entities on the request, with a logging only mode that masks what reaches your logging callbacks while the provider sees the original text. Secret detection strips API keys and tokens from the request before the provider sees them. Logging has three redaction switches: turn_off_message_logging (redact messages and response content), redact_user_api_key_info (redacting UserAPIKeyInfo), and redact_messages_in_exceptions (redacting messages from alerts). Spend logs store no prompt or response text unless store_prompts_in_spend_logs is set (config settings). Virtual keys are stored as SHA-256 hashes (virtual keys), /model/info masks provider credentials (model management), and LITELLM_SALT_KEY encrypts model litellm_params, stored environment variables, and MCP credentials in the database (data at rest encryption). Client-facing errors run through an internal-detail scrub that removes secrets, system paths, private IPs, and tracebacks, and request validation errors (422) leave the submitted body out of the response (error responses and headers)
How to turn it on. Key hashing, credential masking, and error scrubbing are always on. Everything else is opt-in: define the PII and secret guardrails, set the three redaction flags under litellm_settings, leave store_prompts_in_spend_logs unset, and set LITELLM_SALT_KEY before the first model is stored
Known limits. Secret detection is an enterprise feature and scans the request only, so a provider that echoes a secret back is not redacted on the response. All three redaction flags default to off, and with them off every logging callback receives full prompts and responses. Encryption at rest covers model litellm_params, environment variables, and MCP credentials; guardrail litellm_params (which can hold a provider API key), non-string values, and the router_settings, general_settings, and litellm_settings sections are stored as plaintext (PR #43255 is in review to extend the coverage). The exact-match response cache is keyed on the request alone, so two keys or teams sending an identical request share one cached response unless you set cache.namespace in the config or metadata.redis_namespace on the request; only the semantic cache is scoped per tenant (caching)
LLM03 Excessive Agency​
The entry moved up three places in 2026 on the back of agentic deployments: agents with more capability, permission, or autonomy than the task needs
What ships. MCP access follows a permission hierarchy across organization, team, and key, with require_key_mcp_access_defined to refuse keys that carry no MCP list and a no-mcp-servers opt-out. Below the server level, tool allow and deny lists, per-entity tool permissions, and toolsets narrow which tools a key or team can call, grants attach servers to keys and teams, the client allowlist limits which MCP client applications may connect, and zero-trust MCP signs a JWT with the caller's identity so the MCP server can enforce its own policy. For function tools the model asks your application to run, the tool permission guardrail and tool policies allow or deny by tool name and argument. For agent-to-agent traffic, A2A agent permissions, the A2A kill switch, and A2A iteration budgets (max_iterations and max_budget_per_session) bound what an agent can do and for how long. A key's models and allowed_routes (virtual keys) limit which models and which proxy routes it can reach at all
How to turn it on. Set mcp_servers or an access group on the key, team, or organization, and set require_key_mcp_access_defined: true to close the default. Create tool policies through the management API or the Admin UI. Put agent_permissions on the key or team, and send metadata.session_id on every call so iteration budgets can count
Known limits. MCP and A2A access is open until some level defines a list: a key with no MCP list on it, its team, or its organization reaches every server, and A2A agents behave the same way. When the permission lookup fails because the database is unreachable, MCP falls back to the global list plus the key's own submitted servers and A2A returns unrestricted access. There is no server-side approval step per tool call; require_approval on Responses API MCP tools is honored by the client, so a human-in-the-loop step has to live in your agent. Tool policies see only tool calls that pass through the gateway; a tool your application runs on its own is invisible to them. A pass-through endpoint defined in YAML is unauthenticated unless its entry sets auth: true (PR #43250 is in review to apply policy checks to entries that omit it)
LLM04 Supply Chain​
The 2026 entry adds a demand to verify that model artifacts match their claimed identity, alongside the classic dependency, image, and plugin risks
What ships. Every published image is signed with cosign, built from a Chainguard Wolfi base pinned by digest, and available in a non-root variant (Docker image security, with a pin by digest recipe). Python dependencies install frozen from uv.lock, and the resolver refuses any package version published in the last three days, so a freshly compromised release cannot enter a build. In CI, Grype scans every Dockerfile's image and OSV scans the lockfile nightly and on pull requests, every third-party GitHub Action is pinned to a commit SHA, zizmor lints the workflows, and OpenSSF Scorecard runs weekly. At runtime, request bodies that carry api_base, base_url, or similar fields are rejected so a caller cannot point the gateway at another upstream (client-side auth), model access groups grant named sets of models instead of raw model names, and MCP servers proposed by a team stay inactive until a proxy admin approves them, with stdio servers limited to an allowlisted command (npx, uvx, python, python3, node, docker, deno, plus LITELLM_MCP_STDIO_EXTRA_COMMANDS) (MCP server submissions)
How to turn it on. The image, lockfile, CI, api_base block, and stdio allowlist controls are on with no setting. Verify signatures with the steps on the image security page and pin by digest in your deployment. Access groups need model_info.access_groups on the deployment and the group name on the key or team
Known limits. The image publish pipeline is not in the public repository, so you can verify a signature with the public key but there is no SBOM or provenance attestation shipped with the image. The default image runs as root; use the -non_root variant. Scans skip pull requests from forks and run on merge and nightly instead, CI jobs have no egress lockdown, and CODEOWNERS covers the UI, cost maps, and migrations but not the workflows, pyproject.toml, uv.lock, or the Dockerfiles. The model cost map is downloaded at startup from the GitHub main branch over HTTPS without a signature; its integrity check is a minimum model count and a shrink ratio, with a fallback to the bundled copy on failure. Set LITELLM_LOCAL_MODEL_COST_MAP=True to use the bundled copy (disable pulling live model prices) or serve your own. A config file or custom callback module loaded from S3 or GCS at boot (load config from S3 or GCS) is written to disk without a checksum, so bucket write access is config write access. A custom code guardrail runs admin-supplied Python under RestrictedPython with no CPU or wall-clock limit, and its http_request primitive can reach private addresses (PR #43280 is in review for both). LiteLLM never downloads or runs model weights; it calls hosted or self-hosted model APIs, so verifying that a model artifact matches its claimed identity stays with whoever serves the model
LLM05 Data and Model Poisoning​
The 2026 entry widens from training data to RAG knowledge bases, agent memory, and fine-tune backdoors
What ships. Uploads through /v1/files accept max_file_size_mb, max_batch_file_size_mb, and allowed_file_extensions (restrict file uploads), and every upload rejects a filename with a path traversal or NUL byte. Batch guardrails run your pre-call guardrails over every record of a purpose=batch JSONL file before it reaches the provider. Inline uploads to /v1/rag/ingest are typed by magic bytes, capped at 512 MiB, and refused when they are archives or executables. Managed prompts can be created, changed, or deleted only by a proxy admin (prompt management), and a model without a team can be registered only by a proxy admin (model management). Fine-tuning jobs are an enterprise feature whose training and validation file ids are checked against the calling key's ownership when they are LiteLLM-managed ids (fine-tuning)
How to turn it on. The filename check, the RAG ingest checks, and the admin-only writes are always on. The /v1/files limits are set under general_settings. Batch guardrails need nothing beyond a pre-call guardrail on the key, team, or request
Known limits. The /v1/files size and extension limits are all unset by default. The RAG ingest malware scanner is a placeholder that recognizes only the EICAR test string, with no configuration hook for a real engine, and uploads referenced by file_url or file_id, or attached to a vector store through /v1/vector_stores/{id}/files, skip the ingest checks (PR #43244 is in review for a configurable scanner and upload controls on every vector store upload route). Fine-tuning files are not scanned and any key can start a job once the enterprise gate is passed. On enterprise, a team admin can register a team-scoped model with its own api_base and pricing. Batch guardrails run pre-call guardrails only, not post-call or deployment-level ones (limits). Poisoning inside a provider's training data, a third-party model, or a knowledge base you fill outside the gateway is out of its view
LLM06 Unbounded Consumption​
The entry moved up four places in 2026 and now names denial of wallet explicitly
What ships. Budgets apply at every level: the whole proxy, organizations, teams, team members, internal users, virtual keys, end users, tags, and model access groups (set budgets, team budgets, tag budgets, access group budgets). Requests per minute, tokens per minute, and parallel request limits apply per key, team, user, model, and tag, with counters shared across instances through Redis (set rate limits, multi-instance rate limiting). When a counter cannot be verified, fail_closed_budget_enforcement (hard budget enforcement) and fail_closed_rate_limit_enforcement (hard rate limit enforcement) reject with 503 instead of admitting. Per-worker admission control caps in-flight requests with a bounded queue, max_request_size_mb and max_response_size_mb cap body sizes, upperbound key params put a ceiling on what /key/generate may ask for, pass-through routes time out after 600 seconds by default (request timeouts), and litellm_settings.block_requests_for_models_without_pricing: true refuses a model the cost map cannot price with a 403 of type model_cost_map_missing, so no spend goes unmetered
How to turn it on. Set max_budget and the rpm_limit, tpm_limit, and max_parallel_requests fields on the key, team, or user; set the two fail-closed flags, max_in_flight_requests_per_worker, and the size caps under general_settings; set upperbound_key_generate_params under litellm_settings
Known limits. Every limit above is unset by default; the pass-through timeout is the only one that is on. A proxy admin key passes authentication before the budget and rate limit checks run, so it is exempt from both. A team-scoped key skips the personal user budget unless general_settings.apply_user_budget_to_team_keys: true. Budgets are checked on LLM API routes only, not on management or utility routes. The global max_budget needs a database and is not enforced without one. With the fail-closed flags off, a Redis outage degrades to per-instance counters; with fail_closed_budget_enforcement on, tag budgets still admit because their counters live in Redis only, and access group budgets are a plain read with no reservation. The body size caps are enterprise-only and are logged and skipped otherwise. There is no per-key ceiling on max_tokens, so output volume is bounded by tokens per minute and budget rather than per request
LLM07 Misinformation​
The entry moved up two places on incident data, with the new emphasis on a wrong answer that drives a tool call or a decision
What ships. Three guardrails check a response against source material: Bedrock Guardrails contextual grounding with contextual_grounding_from_messages, the Qualifire hallucination and grounding checks, and XecGuard context grounding, which reads the documents from metadata.xecguard_grounding_documents. The LLM-as-a-judge guardrail has a second model score the response against your own rubric and blocks below overall_threshold (80 by default). For models that are about to be retired, GET /model/deprecations lists deployments whose provider deprecation date falls within warn_within_days (30 by default), and the Slack model_deprecation_warnings alert fires once alerting is configured
How to turn it on. Define the grounding or judge guardrail with mode: post_call, attach it to the keys or teams that need it, and pass the source documents where the provider expects them. Deprecation warnings need only the alerting setup
Known limits. Every check here is opt-in, adds a provider or model call to the request, and is probabilistic. A grounding check needs the source documents on the request or in metadata, so a RAG flow that retrieves outside LiteLLM has to pass them along. Nothing verifies a factual claim without a source document, and a wrong answer that turns into a tool call is checked against tool policy (LLM03), not against truth. The gateway cannot tell an overconfident answer from a correct one on its own
LLM08 Hidden Context Exposure​
Renamed from System Prompt Leakage in 2026 and widened to developer instructions, RAG policy text, user profiles, and tool schemas, with the advice to assume all of it can be disclosed
What ships. Managed prompts keep the developer message server-side so callers send a prompt_id and variables instead of the prompt itself (prompt management), and only a proxy admin can write them. The Content Filter prompt_injection_system_prompt pattern blocks requests that ask for the system prompt, and the Bedrock PROMPT_LEAKAGE check does the same through Bedrock. The LLM02 redaction switches keep prompts out of logs, alerts, and spend logs, and logging only PII masking masks what your logging callbacks receive. Client headers are not forwarded to providers unless forward client headers is configured, internal _hidden_params are stripped from responses, and error messages run through the internal-detail scrub described under LLM02
How to turn it on. Move secrets and policy text out of prompts first; nothing on this page makes a prompt unreadable to the model that receives it. Then define the Content Filter or Bedrock guardrail with mode: pre_call and set the redaction flags under litellm_settings
Known limits. A model can be talked into repeating its context, and the gateway's checks catch the direct asks by pattern; the Bedrock check runs on the request side only. Redaction is off by default, and the Responses API instructions and tools fields are not covered by message redaction, so they reach callbacks in full even with turn_off_message_logging set. The prompt list and info endpoints honor a prompts allowlist in the key's metadata, but resolving a prompt_id at request time has no access check, so any key that can call the model can use any prompt id it knows. The x-litellm-model-api-base response header always names the upstream host (the query string is removed), and a public provider hostname can appear in the API Base: line of a client-facing error. Any authenticated key can list the configured guardrails' names and masked parameters through the v1 /guardrails/list route
LLM09 Vector and Embedding Weaknesses​
The entry covers poisoned chunks, weak access control on the store, and embedding inversion
What ships. Keys and teams can be restricted to specific vector stores through object_permission.vector_stores, stores can be scoped to a team, and disable_vector_stores_for_internal_users keeps internal users out entirely. The ingest checks under LLM05 apply to inline uploads. The vector store page describes retrieved context going through your pre-call guardrails, which is the intended place to catch a poisoned chunk before the model sees it
How to turn it on. Set object_permission.vector_stores on the key or team, set team_id on the store, and set disable_vector_stores_for_internal_users: true under general_settings when internal users should not query stores
Known limits. Access is per store, not per document. An empty vector_stores list means every store is allowed, and a store with no team_id is usable by any key that can use vector stores at all. At version 1.104.0 the retrieved chunks are added to the request after the pre-call guardrails have already run, so the scan the vector store page describes does not happen until PR #43271 lands; until then a post_call guardrail sees the model's use of the chunks, not the chunks themselves. The malware scanner on ingest is the placeholder described under LLM05. Embedding inversion and the store's own encryption and access controls belong to the vector database; the gateway holds its credentials and forwards queries
LLM10 Improper Output Handling​
The entry dropped five places in 2026 but still covers unvalidated output reaching browsers, databases, shells, and APIs, and insecure generated code
What ships. Any guardrail with mode: post_call inspects or rewrites the response before the client sees it, and the tool permission guardrail checks the tool calls a response asks for. On streams, streaming_buffer_until_moderated, streaming_sampling_rate, streaming_end_of_stream_only, and streaming_transform_mode decide whether the stream is held until it passes or sampled as it flows (streaming and post_call guardrails), with Bedrock and the Content Filter documenting their own stream behavior. Output parsing in the PII guardrail masks entities on the response. The Admin UI renders model output as Markdown without raw HTML
How to turn it on. Define the guardrail with mode: post_call, attach it, and set streaming_buffer_until_moderated: true on it when a block must land before any chunk reaches the client
Known limits. Every output guardrail is opt-in. On a stream, a post_call guardrail that is not buffering runs on the assembled response after the chunks are already delivered, so it can audit but not block; only Bedrock, Straiker, and Rubrik buffer by default, the rest sample every fifth chunk, and the OpenAI moderation guardrail samples rather than buffers. PII output parsing does not cover raw byte streams from providers other than Anthropic or /v1/responses stream events, and logs a warning when it skips them. The gateway does not validate generated code, SQL, HTML, or shell commands against what your application will do with them; treat model output as untrusted input in every consumer. The Admin UI loads remote images referenced in model output automatically (PR #43276 is in review to make that click-to-load)
Keeping this page current​
The OWASP list is at genai.owasp.org and this page tracks its 2026 edition. The controls and limits above were checked against LiteLLM main at version 1.104.0; the pull requests linked as in review change a limit when they merge, so check their state against the version you run. If a control on your version behaves differently from what this page says, open an issue on BerriAI/litellm with the version and the section name