惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 三生石上(FineUI控件)
WordPress大学
WordPress大学
阮一峰的网络日志
阮一峰的网络日志
大猫的无限游戏
大猫的无限游戏
T
Tailwind CSS Blog
S
SegmentFault 最新的问题
The Hacker News
The Hacker News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
小众软件
小众软件
Google DeepMind News
Google DeepMind News
腾讯CDC
博客园 - 司徒正美
Cisco Talos Blog
Cisco Talos Blog
Apple Machine Learning Research
Apple Machine Learning Research
The Cloudflare Blog
博客园 - 聂微东
博客园 - 【当耐特】
Project Zero
Project Zero
有赞技术团队
有赞技术团队
量子位
P
Privacy International News Feed
博客园_首页
酷 壳 – CoolShell
酷 壳 – CoolShell
J
Java Code Geeks
IT之家
IT之家
SecWiki News
SecWiki News
H
Hacker News: Front Page
PCI Perspectives
PCI Perspectives
L
Lohrmann on Cybersecurity
宝玉的分享
宝玉的分享
Cloudbric
Cloudbric
雷峰网
雷峰网
月光博客
月光博客
Cyberwarzone
Cyberwarzone
S
Securelist
Hugging Face - Blog
Hugging Face - Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
博客园 - Franky
T
Threat Research - Cisco Blogs
罗磊的独立博客
Forbes - Security
Forbes - Security
NISL@THU
NISL@THU
N
News and Events Feed by Topic
T
Troy Hunt's Blog
Jina AI
Jina AI
Hacker News - Newest:
Hacker News - Newest: "LLM"
C
Cyber Attacks, Cyber Crime and Cyber Security
The Last Watchdog
The Last Watchdog
V2EX - 技术
V2EX - 技术

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
OWASP LLM Top 10 in Production: How I Audited My TypeScript Agent Pipeline Against All 10 Risks — and What I Found
Juan Torchia · 2026-06-20 · via DEV Community

OWASP LLM Top 10 in Production: How I Audited My TypeScript Agent Pipeline Against All 10 Risks — and What I Found

I was reviewing a system prompt for an MCP agent I'd written three weeks earlier when something hit me hard: the prompt was accepting instructions from the output of an external tool. No sanitization. No validation. No limits whatsoever on what it could do with that output. The tool called a public API, got back JSON, and that JSON landed directly in the model's context.

That's when I opened the OWASP LLM Top 10 and stopped reading it like a list of best practices — and started using it for what it actually is: an audit framework.

My thesis is simple: most posts about the OWASP LLM Top 10 explain the ten risks to you. None of them show you how to run them against your own stack and what you actually find when you do it seriously. That's the difference between "reading the checklist" and "auditing the pipeline." This post is the second thing.


The Stack I Audited — and Why Context Matters

Before getting into the checklist, some context: I have a TypeScript agent pipeline with three layers that interact with each other:

  1. Structured system prompts — instructions that define agent behavior, kept separate from user context
  2. MCP tools — tools registered following the Model Context Protocol, which the agent can call during a session
  3. Cline as the client — orchestrating execution inside the editor, with access to filesystem, terminal, and other tools

Each layer has a different attack surface. That's exactly what the OWASP LLM Top 10 let me see with surgical precision.


All 10 Risks: What I Found in Each One

LLM01 — Prompt Injection

This was the biggest finding. My MCP agent was receiving output from external tools and injecting it directly into context with zero sanitization layer. In an adversarial scenario, any API the agent queried could return text specifically crafted to overwrite the system prompt instructions.

The broken pattern looked like this:

// ❌ Insecure pattern: external output goes straight into context
async function fetchContextAndInject(url: string): Promise<string> {
  const response = await fetch(url);
  const data = await response.json();
  // data.content reaches the model context with no filtering whatsoever
  return data.content;
}

What I changed it to:

// ✅ Structural validation before injecting into context
import { z } from "zod";

const ExternalResponseSchema = z.object({
  // Only accept fields with defined types — free-form strings flagged as suspicious
  title: z.string().max(200),
  summary: z.string().max(1000),
  // Anything not in the schema gets discarded
});

async function fetchContextSafe(url: string): Promise<string> {
  const response = await fetch(url);
  const raw = await response.json();
  // If the schema fails, the agent gets a structured error — not the raw payload
  const parsed = ExternalResponseSchema.parse(raw);
  return `Title: ${parsed.title}\nSummary: ${parsed.summary}`;
}

I used Zod — which was already in the stack for API validation — as the first line of defense. It's not a complete solution to prompt injection, but it reduces the structural attack surface.

LLM02 — Insecure Output Handling

The second problem: agent output was reaching the UI without escaping. In an agent that generates HTML or Markdown, that's potential XSS if the output gets rendered directly.

I traced every place where model output touched the DOM and added explicit sanitization before any render. If the agent generates code, that code goes into a <pre> block with escaped characters — not into an innerHTML.

LLM03 — Training Data Poisoning

Here the OWASP LLM Top 10 points to risks in the base model, not the application. In my case the model is Claude via API — I don't control the fine-tuning or the dataset. My only action was to document this dependency explicitly: if Anthropic has a problem here, I have a problem here. No system prompt compensates for that.

Honest limit: you can't audit this from the application layer. It's a dependency you take as a trust boundary.

LLM04 — Model Denial of Service

I checked whether I had rate limiting on the endpoints that trigger model calls. I didn't — at least not in the local testing context. In a production scenario this is critical: a badly designed loop or a tool that calls recursively can fire dozens of model requests in seconds.

I added a simple iteration cap to the agent loop:

// Iteration control to prevent infinite loops in the agent
const MAX_ITERATIONS = 10;
let iterations = 0;

while (agentShouldContinue && iterations < MAX_ITERATIONS) {
  iterations++;
  const result = await runAgentStep();
  agentShouldContinue = result.continueLoop;
}

if (iterations >= MAX_ITERATIONS) {
  // Explicit log — I want to know if this ever fires
  console.warn("[agent] Iteration limit reached — review loop");
}

LLM05 — Supply Chain Vulnerabilities

This risk made me look at two things: the npm packages I use to interact with the model API, and the dependencies of my MCP tools. With pnpm workspaces (something I covered in the monorepo with Railway post) you get lockfile visibility — but that's not the same as auditing.

What I added: pnpm audit as an explicit CI step before deploying any agent. It doesn't eliminate the risk, but it makes it visible.

LLM06 — Sensitive Information Disclosure

This is where the second uncomfortable finding showed up: my system prompts contained configuration context that included names of internal tools, data structure details, and some system defaults. That context reaches the model — and if the model echoes it in its output, it's exposed.

The rule I applied: nothing you wouldn't want to see in a public log should be in a system prompt without explicit confidentiality marking. And even that isn't a guarantee — it's mitigation.

// Separate technical config from agent instructions
const SYSTEM_PROMPT_PUBLIC = `
You are a development assistant. You can use available tools
to answer technical questions.
`;

// This does NOT go into the system prompt — it lives in a separate config layer
const AGENT_CONFIG_PRIVATE = {
  toolEndpoints: process.env.TOOL_ENDPOINTS,
  internalSchema: process.env.INTERNAL_SCHEMA,
};

LLM07 — Plugin Design Flaws

My MCP tools are essentially plugins. The risk here is that a tool has broader permissions than it actually needs. I reviewed each tool and applied least privilege: a tool that reads files doesn't need write access; a tool that queries an API doesn't need filesystem access.

This connects directly to what I wrote about OAuth scope creep — the same audit pattern applies to an agent's tools.

LLM08 — Excessive Agency

This is the risk that concerns me most specifically with Cline. The agent has terminal access, can execute commands, can modify files. If the reasoning loop fails, it can cause real damage.

What I implemented: "confirm before execute" mode for any tool with an irreversible side effect. It's not automatable — it requires deliberate human friction. And that friction is the entire point.

// Explicit tool classification by impact
type ToolImpact = "read-only" | "reversible" | "destructive";

const TOOL_IMPACT_MAP: Record<string, ToolImpact> = {
  readFile: "read-only",
  listDirectory: "read-only",
  writeFile: "reversible",
  deleteFile: "destructive",
  runCommand: "destructive",
};

async function executeTool(toolName: string, args: unknown) {
  const impact = TOOL_IMPACT_MAP[toolName] ?? "destructive"; // safe fallback
  if (impact === "destructive") {
    // Pause and wait for human confirmation before executing
    await requireHumanApproval(toolName, args);
  }
  return runTool(toolName, args);
}

LLM09 — Overreliance

This isn't a purely technical risk — it's organizational. The problem is trusting the agent's output without external validation. In my pipeline, any output going to production passes through a structural validation layer before it's used as input to another system. The model can be fine, the pipeline can be fine, and the output can still be wrong.

This risk doesn't close with code. It closes with process and human review at critical nodes.

LLM10 — Model Theft

In my TypeScript agent context, this mainly applies to protecting system prompts. A well-crafted system prompt represents real work — and if it leaks, it can be replicated or used to bypass restrictions.

What I implemented: system prompts don't live in frontend code. They're served from an authenticated endpoint, they're not logged in plain text, and they don't get exposed in the client bundle.


What the OWASP LLM Top 10 Doesn't Tell You (Which Matters Just as Much)

Here's what the list doesn't resolve on its own:

It doesn't tell you the priority order for your stack. LLM01 (prompt injection) was critical in my case; LLM03 (training data poisoning) is irrelevant from the application layer. Without applying it against your concrete architecture, you don't know which one is urgent.

It gives you no criteria for the trust boundary of the base model. If you use Claude, GPT-4, or any external API, LLM03 and part of LLM05 are dependencies you take as given. The framework names them, but the mitigation is out of your hands.

It doesn't distinguish between runtime risks and design risks. LLM01 and LLM02 are problems you can detect and mitigate at runtime. LLM08 (excessive agency) is a design problem — if the agent has too many permissions, a runtime patch doesn't fix it.

I have a post on OpenTelemetry in Next.js where I talk about traces that survive the edge. That kind of observability helps here too: if you can't see which tools the agent called and with what args, you can't audit LLM08 in production.


Applied Checklist: The Real State of Each Risk in My Pipeline

Risk State Found Action Taken
LLM01 Prompt Injection ❌ Vulnerable Zod schema on external tool output
LLM02 Insecure Output ⚠️ Partial Explicit escaping before render
LLM03 Training Data 🔵 Out of scope Documented as trust boundary
LLM04 Model DoS ⚠️ No limit Added max iterations + log
LLM05 Supply Chain ⚠️ Invisible pnpm audit in CI
LLM06 Info Disclosure ❌ Leaky prompts Separated config from system prompt
LLM07 Plugin Flaws ⚠️ Partial Permission review per tool
LLM08 Excessive Agency ⚠️ No friction Confirm before execute on destructive tools
LLM09 Overreliance 🔵 Process Human validation at critical nodes
LLM10 Model Theft ⚠️ Prompts exposed Prompts moved to authenticated endpoint

❌ = critical finding | ⚠️ = partial mitigation | 🔵 = outside application control


FAQ

Does the OWASP LLM Top 10 apply to agents built on Claude or GPT-4 via API?

Yes, with nuance. LLM01, LLM02, LLM06, LLM07, LLM08, and LLM10 are application-layer risks — they apply regardless of which model you use. LLM03 (training data) and part of LLM05 are provider risks: if you use an external API, you take them as a trust boundary. The audit starts with the risks you can actually control.

Is Zod enough to mitigate prompt injection?

No. Zod validates the structure of external output before it reaches context — that reduces the surface area, but it doesn't eliminate the risk. A well-formed adversarial payload can pass schema validation. Zod is one layer, not a complete solution. Real mitigation combines schema validation, system prompt constraints, and human review at critical points.

Is Cline safe to use in production as an agent orchestrator?

Cline has access to the filesystem, terminal, and other tools with real effects. That's not inherently unsafe — it's the functionality that makes it useful. The risk (LLM08) is in the design: if the agent can execute destructive commands without human confirmation, the risk is real regardless of how well Cline is configured. My rule: any tool with an irreversible effect requires explicit approval.

How often should you run this audit?

Every time you change the agent's architecture: you add a new tool, change the system prompt, or modify how the agent consumes external outputs. It's not a one-time audit — it's a checklist that runs against every structural change. If you add observability (OpenTelemetry is one option), you can catch runtime anomalies between audits.

Does the OWASP LLM Top 10 cover multi-agent risks or just single-agent?

The current version (2025) primarily covers per-agent risk. In multi-agent architectures, LLM01's surface multiplies: each agent can become an injection vector for the others. The framework names the risk, but the mitigation detail for multi-agent pipelines is left to each team.

Which risk should I tackle first if I have limited time?

LLM01 (prompt injection) if your agent consumes external output — it's the most exploitable and the most overlooked. LLM08 (excessive agency) if the agent has access to tools with irreversible effects — it's the one that can do the most damage when something goes wrong. The rest depend on your specific stack, but these two are the absolute floor.


The Difference Between Reading and Auditing

My position is clear: the OWASP LLM Top 10 is not something you read and consider covered. It's something you bring into a review session with the architecture diagram open in front of you, and you ask — for each risk — exactly where in the pipeline that could fail.

What I don't buy is the idea that "following best practices" is enough. Practices are abstract; the pipeline is concrete. In my case, LLM01 and LLM06 were real problems I wouldn't have found without doing the systematic audit exercise. I would have discovered them when someone motivated enough decided to exploit them.

If you already have TypeScript agents with MCP tools or elaborate system prompts, do the exercise: open the OWASP LLM Top 10, open the architecture diagram, and ask risk by risk. The result will be more interesting than the list itself.

Concrete next step: take the checklist from this table, replace the states with your own, and document the findings. An audit that isn't documented doesn't exist.


Original source:


This article was originally published on juanchi.dev