Skip to content
guide

OWASP Top 10 for agentic apps: what API developers need to change

| 10 min read
Shield icon on dark background representing application security framework
Photo by FLY:D on Unsplash

Your API has rate limiting, BOLA checks, and input validation. An AI agent bypasses all three by chaining six authorized endpoints into a privilege escalation path your threat model never considered. 520 tool misuse incidents in early 2026 reporting confirm this isn't theoretical.

OWASP released its Top 10 for Agentic Applications in 2026, built by 100+ security researchers from Cisco, Microsoft, Google, and the broader community. The list targets a new threat surface: autonomous AI agents that call your APIs, retain memory, and make decisions without human approval.

The original OWASP API Security Top 10 assumes a human clicks a button and triggers one request. The agentic list assumes a machine fires 50 requests in a chain, each informed by the previous response, with no human in the loop. Same APIs, different attacker profile.

This guide covers the five OWASP agentic risks that API developers can fix at the API layer, with working code you can ship this week.

The agentic action layer: why your APIs are the attack surface

APIs have evolved into what security researchers now call the "agentic action layer." Every tool an AI agent uses, whether ordering inventory, querying a database, or sending a notification, maps to an API call. The agent doesn't interact with a UI. It reads your OpenAPI spec, discovers endpoints, and calls them in sequence.

48.9% of organizations have no visibility into machine-to-machine traffic. That means half of all API infrastructure cannot distinguish a human user from an autonomous agent. If you can't tell the difference, you can't enforce different rules.

The OWASP Agentic Top 10 covers: Excessive Agency, Prompt Injection, Supply Chain Vulnerabilities, Memory Poisoning, Tool Misuse and Privilege Escalation, Cascading Failures, Insecure Output Handling, Insufficient Logging, Data Leakage, and Inadequate Sandboxing. This guide focuses on the five risks you fix at the API layer.

1. Excessive agency: agents calling endpoints they shouldn't

A customer support agent needs to read order status. You give it an API key with access to your entire API. The agent discovers it can also cancel orders, issue refunds, and delete accounts. Excessive agency means the agent has permissions beyond its task.

This is the agentic equivalent of OWASP API5 (broken function-level authorization), but the attack vector is different. A human attacker discovers admin endpoints through source code or URL guessing. An agent discovers them through your OpenAPI spec or tool manifest. The agent doesn't need to guess; you handed it the full menu.

Fix: scoped API keys and endpoint allowlists

Create one API key per agent. Each key maps to an explicit list of allowed endpoints. Reject any request outside that list.

// Scoped API key configuration per agent
const agentPermissions = {
  "agent-order-bot": {
    allowedEndpoints: [
      "GET /api/orders/:id",
      "GET /api/orders/:id/status"
    ],
    rateLimit: { requests: 20, windowSeconds: 60 },
    maxChainDepth: 3
  },
  "agent-support-bot": {
    allowedEndpoints: [
      "GET /api/orders/:id",
      "POST /api/tickets",
      "GET /api/tickets/:id"
    ],
    rateLimit: { requests: 10, windowSeconds: 60 },
    maxChainDepth: 5
  }
};

// Middleware: check agent scope before processing
function enforceAgentScope(req, res, next) {
  const agentId = req.headers["x-agent-id"];
  const permissions = agentPermissions[agentId];

  if (!permissions) {
    return res.status(403).json({ error: "Unknown agent" });
  }

  const route = `${req.method} ${req.route.path}`;
  if (!permissions.allowedEndpoints.includes(route)) {
    return res.status(403).json({
      error: "Endpoint not in agent scope",
      agent: agentId,
      attempted: route
    });
  }

  next();
}

To verify that an agent's JWT carries the correct scope before processing, inspect the token claims. The /v1/jwt/decode endpoint decodes any JWT without needing the signing key, so you can audit token contents during development and in your CI pipeline:

curl -s -X POST https://api.botoi.com/v1/jwt/decode \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZ2VudC1vcmRlci1ib3QiLCJzY29wZSI6Im9yZGVycy5yZWFkIiwiaWF0IjoxNzQ5NTY0ODAwLCJleHAiOjE3NDk1NjgwMDB9.signature"
  }'

Response:

{
  "success": true,
  "data": {
    "header": {
      "alg": "RS256",
      "typ": "JWT"
    },
    "payload": {
      "sub": "agent-order-bot",
      "scope": "orders.read",
      "iat": 1749564800,
      "exp": 1749568000
    }
  }
}

The scope claim says orders.read. If this agent calls POST /api/orders/:id/cancel, your middleware should reject the request before it reaches your handler.

2. Tool misuse and privilege escalation: agents chaining API calls

Tool misuse logged 520 incidents in early reporting, making it the most common agentic threat. The pattern: an agent calls endpoint A, extracts data from the response, then uses that data to call endpoint B in a way the developer never anticipated.

Developer reviewing code on screen representing API security audit
520 tool misuse incidents in H1 2026; most exploited APIs with no per-agent rate limits Photo by Kevin Ku on Unsplash

Example: A Stripe integration agent has access to GET /api/customers/:id and POST /api/refunds. The agent reads a customer's payment history, identifies the highest-value transaction, and issues a refund to itself. Each individual call passes authorization. The chain is the exploit.

Fix: per-agent rate limits and chain depth tracking

Standard rate limiting counts requests per IP or per API key. Agentic rate limiting adds two dimensions:

  • Per-tool limits: Cap how many times a single agent can call a specific endpoint within a window
  • Chain depth limits: Track how many sequential API calls an agent makes in a single session and cut it off at a defined threshold
Rate limit type What it catches Who needs it
Per-IP DDoS, credential stuffing Every API
Per-API-key Abusive individual consumers Every API
Per-agent-per-tool Agent calling one endpoint in a loop APIs consumed by agents
Chain depth Multi-step privilege escalation APIs consumed by agents

Require agents to send an X-Agent-Session header. Track the call count per session. When the count exceeds your threshold, return a 429 with a clear error message.

3. Insufficient logging: no visibility into agent API calls

48.9% of organizations are blind to machine-to-machine traffic. When an agent exploits your API, you need to answer: which agent? Which endpoints? In what order? Over what time window? Standard access logs show IP addresses and timestamps. They don't show agent identity or call sequences.

The OWASP agentic list flags insufficient logging as a top risk because agent attacks look like authorized traffic. Every individual request passes auth. The exploit lives in the pattern across multiple requests.

Fix: require attribution headers and log call chains

Add three required headers for agent consumers:

  • X-Agent-ID: unique identifier for the agent (tied to its API key)
  • X-Agent-Session: identifier for the current task or conversation
  • User-Agent: agent framework and version (e.g., LangChain/0.3.1)
// Middleware: log every agent request with attribution
function agentAuditLog(req, res, next) {
  const logEntry = {
    timestamp: new Date().toISOString(),
    agentId: req.headers["x-agent-id"] || "unknown",
    apiKey: req.headers["x-api-key"]?.slice(-8) || "none",
    method: req.method,
    path: req.path,
    sessionId: req.headers["x-agent-session"] || "none",
    ip: req.ip,
    userAgent: req.headers["user-agent"]
  };

  // Structured JSON log for your SIEM
  console.log(JSON.stringify(logEntry));

  // Track chain depth per session
  const session = req.headers["x-agent-session"];
  if (session) {
    const depth = chainTracker.increment(session);
    if (depth > MAX_CHAIN_DEPTH) {
      return res.status(429).json({
        error: "Agent chain depth exceeded",
        maxDepth: MAX_CHAIN_DEPTH,
        currentDepth: depth
      });
    }
  }

  next();
}

This middleware logs every request as structured JSON, which feeds into any SIEM or log aggregator. It also enforces chain depth by tracking sequential calls per session. When you investigate an incident, you can reconstruct the full chain by filtering on sessionId.

4. Insecure output handling: agents trusting API responses without validation

An agent calls your API, receives a JSON response, and passes it to the next step in its chain. If the response contains unexpected fields, wrong types, or injected content, the agent propagates the problem downstream. This is the agentic equivalent of OWASP API10 (unsafe consumption of APIs), amplified by the fact that agents process responses automatically with no human review.

Example: A competitor compromises a third-party pricing API. The agent fetches product prices, receives a response with a manipulated price field set to 0.01, and places an order at that price. No human ever saw the response.

Fix: validate every response against a JSON Schema

Start by generating a schema from a known-good response. The /v1/schema/json-to-jsonschema endpoint produces a JSON Schema from any sample JSON:

curl -s -X POST https://api.botoi.com/v1/schema/json-to-jsonschema \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "json": {
      "orderId": "ord_12345",
      "status": "shipped",
      "total": 49.99,
      "items": [
        { "sku": "WIDGET-A", "quantity": 2 }
      ]
    }
  }'

Response:

{
  "success": true,
  "data": {
    "schema": {
      "type": "object",
      "properties": {
        "orderId": { "type": "string" },
        "status": { "type": "string" },
        "total": { "type": "number" },
        "items": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "sku": { "type": "string" },
              "quantity": { "type": "integer" }
            }
          }
        }
      }
    }
  }
}

Then validate every response your agent receives against that schema. The /v1/schema/validate endpoint checks a JSON object against any JSON Schema and returns specific errors:

curl -s -X POST https://api.botoi.com/v1/schema/validate \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "schema": {
      "type": "object",
      "required": ["orderId", "status", "total"],
      "properties": {
        "orderId": { "type": "string" },
        "status": { "type": "string", "enum": ["pending", "shipped", "delivered"] },
        "total": { "type": "number", "minimum": 0 }
      },
      "additionalProperties": false
    },
    "data": {
      "orderId": "ord_12345",
      "status": "shipped",
      "total": 49.99,
      "internalNote": "rush order"
    }
  }'

Response:

{
  "success": true,
  "data": {
    "valid": false,
    "errors": [
      {
        "path": "",
        "message": "must NOT have additional properties: internalNote"
      }
    ]
  }
}

The validation caught internalNote, a field that doesn't belong in the response. If an API starts returning unexpected fields, your agent stops processing instead of passing tainted data downstream.

Here's the full pattern using the Botoi Node.js SDK:

import Botoi from "botoi";

const botoi = new Botoi({ apiKey: process.env.BOTOI_API_KEY });

// Step 1: generate a schema from a known-good response
const schemaResult = await botoi.schema.jsonToJsonschema({
  json: knownGoodResponse
});
const responseSchema = schemaResult.data.schema;

// Step 2: validate every agent-received response against that schema
async function validateAgentResponse(response) {
  const validation = await botoi.schema.validate({
    schema: responseSchema,
    data: response
  });

  if (!validation.data.valid) {
    console.error("Response failed validation:", validation.data.errors);
    throw new Error("Untrusted response rejected by schema validation");
  }

  return response;
}

5. Supply chain vulnerabilities: compromised tool definitions

AI agents discover tools through MCP servers, OpenAPI specs, and tool manifests. If an attacker modifies a tool definition, the agent calls a different endpoint, sends data to a different server, or executes with different parameters than the developer intended.

Example: You use an open-source MCP server that defines 30 tools. An attacker submits a pull request that changes one tool's API URL from api.stripe.com to api.str1pe.com. The change passes code review because it's a single character. Your agent now sends payment data to the attacker's server.

Fix: hash tool definitions and verify at runtime

Hash every tool definition at deploy time. Before your agent registers a tool at runtime, hash it again and compare. The /v1/hash endpoint generates a SHA-256 hash of any string:

curl -s -X POST https://api.botoi.com/v1/hash \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "text": "{\"name\":\"get_order_status\",\"description\":\"Retrieve current order status by order ID\",\"parameters\":{\"orderId\":\"string\"}}",
    "algorithm": "sha256"
  }'

Response:

{
  "success": true,
  "data": {
    "hash": "a3f2b8c1d4e5f67890abcdef1234567890abcdef1234567890abcdef12345678",
    "algorithm": "sha256"
  }
}

Here's the full integrity check workflow using the Botoi SDK:

import Botoi from "botoi";
import fs from "fs";

const botoi = new Botoi({ apiKey: process.env.BOTOI_API_KEY });

// Hash every tool definition at deploy time
const toolDefs = JSON.parse(fs.readFileSync("./mcp-tools.json", "utf-8"));
const hashes = {};

for (const tool of toolDefs) {
  const result = await botoi.hash.sha256({
    text: JSON.stringify(tool)
  });
  hashes[tool.name] = result.data.hash;
}

fs.writeFileSync("./tool-hashes.json", JSON.stringify(hashes, null, 2));

// At runtime, verify before registering any tool
async function verifyToolIntegrity(tool) {
  const result = await botoi.hash.sha256({
    text: JSON.stringify(tool)
  });
  const expected = hashes[tool.name];

  if (result.data.hash !== expected) {
    throw new Error(
      `Tool "${tool.name}" failed integrity check. \n` +
      `Expected: ${expected}\n` +
      `Got: ${result.data.hash}`
    );
  }
}

Run the hash generation step in your CI pipeline. Store the hashes file alongside your deployment artifact. At runtime, every tool gets verified before registration. A single changed character in any tool definition triggers a hard failure.

OWASP agentic top 10 vs API Security top 10: comparison

The two lists complement each other. Here's how the five agentic risks map to their closest API Security counterparts and what changes:

Agentic risk Closest API Security risk What changes for agents
Excessive Agency API5 Broken Function Auth Agents discover all endpoints from specs; scope keys per agent
Tool Misuse API4 Resource Consumption Agents chain calls to escalate; add chain depth limits
Insufficient Logging No direct equivalent Agent calls look like authorized traffic; add attribution headers
Insecure Output API10 Unsafe Consumption Agents process responses without human review; add schema validation
Supply Chain No direct equivalent Compromised tool defs redirect agent traffic; add integrity hashes

Ship checklist: five fixes for agentic API security

Each fix is independent. Pick one, ship it, move to the next.

Fix What to do Botoi endpoint
Scoped API keys One key per agent; allowlist endpoints per key /v1/jwt/decode
Per-agent rate limits Track per-tool and per-session chain depth
Attribution headers Require X-Agent-ID, X-Agent-Session; log structured JSON
Response validation Generate schema from good response; validate all agent responses /v1/schema/validate, /v1/schema/json-to-jsonschema
Tool integrity Hash tool defs at deploy; verify at runtime /v1/hash

What comes next

The full OWASP Top 10 for Agentic Applications lives at owasp.org. Cisco, Microsoft, and Google all announced agentic security initiatives at RSAC 2026, so expect tooling and standards to move fast through the rest of the year.

The five remaining risks on the list (Prompt Injection, Memory Poisoning, Cascading Failures, Data Leakage, and Inadequate Sandboxing) require fixes at the agent framework layer, not the API layer. If you run an agent framework, read the full OWASP document. If you run APIs, the five fixes above are your starting point.

Start with scoped API keys. That single change blocks the majority of excessive agency and tool misuse scenarios. Then add attribution headers so you can see what your agents are doing. The rest follows from visibility.

Frequently asked questions

How does the OWASP Agentic Applications Top 10 differ from the OWASP API Security Top 10?
The API Security Top 10 (2023) addresses risks from human consumers: broken authorization, authentication flaws, excessive data exposure. The Agentic Applications Top 10 (2026) addresses risks from autonomous AI agents that chain API calls, retain memory across sessions, and make decisions without human oversight. Both lists apply to APIs, but the agentic list targets machine-to-machine patterns the original never anticipated.
What is excessive agency in agentic applications?
Excessive agency occurs when an AI agent has access to API endpoints or actions beyond what its task requires. For example, a customer-support agent with access to billing, refund, and account deletion endpoints can chain those calls to escalate far beyond answering questions. The fix is scoped API keys that restrict each agent to the exact endpoints it needs.
Do I need to rebuild my API for agentic security?
No. You do not need to rebuild. The five fixes covered in this guide, scoped API keys, per-tool rate limits, request attribution headers, response schema validation, and tool definition integrity checks, are additions to your existing API. You can ship each one independently.
Why is tool misuse the most common agentic application threat?
Tool misuse and privilege escalation logged 520 incidents in early reporting because agents chain API calls in ways developers never intended. A single agent may call a read endpoint, parse the response, then call a write endpoint using data from the first call to escalate privileges. Most APIs have no mechanism to detect or block multi-step chains from a single agent session.
How do I attribute API requests to specific AI agents?
Add a required X-Agent-ID header to your API. Each agent gets a unique identifier tied to its scoped API key. Log both the API key and the agent ID on every request. This gives you a full audit trail of which agent called which endpoint, when, and in what sequence.

Try this API

JWT Decoder API — interactive playground and code examples

More guide posts

Start building with botoi

150+ API endpoints for lookup, text processing, image generation, and developer utilities. Free tier, no credit card.