🌐 This article is also available in: Deutsch

OWASP API Security Top 10 (2023) Explained With Code

Schematic of a REST API annotated with the ten risk categories of the OWASP API Security Top 10 2023

APIs are the backbone of modern software. Mobile apps, single-page applications, microservices, partner integrations, and increasingly AI agents all talk to each other through interfaces (APIs). That is exactly why APIs have become a preferred target: they expose business logic, object references, and data structures with a directness that traditional, server-rendered web applications never had.

The OWASP API Security Top 10 is the authoritative reference list for these specific risks. The current version is the 2023 edition, a ground-up rework of the original 2019 list. This article explains all ten categories edition-accurately (that is, with the exact original 2023 IDs and names), gives every category a vulnerable and a secure code example in one continuous Node.js/Express API, breaks down what changed from 2019 to 2023, and grounds the categories in real incidents, from the classic cases up to breaches from 2023 through 2025.

What sets this guide apart: instead of ten abstract definitions, you get one coherent example API that you see broken and then fixed, category by category. That turns the list into a practical checklist you can hold directly against your own code.

What is the OWASP API Security Top 10?

The OWASP API Security Project is a community-driven project of the Open Worldwide Application Security Foundation. It exists because the general OWASP Top 10 (for classic web applications) does not fully capture the vulnerability patterns typical of APIs. APIs expose direct object references, fine-grained business functions, and machine-readable data structures differently than a classic server-rendered website does.

The central insight of the 2023 rework: many of the most severe API incidents are technically perfectly valid requests. The attacker uses real, valid credentials, calls a real endpoint, and gets real data back. No exploit kit, no memory corruption, no classic injection required. This is precisely why authorization (who is allowed to do what with which object, property, or function) dominates the list, not encryption or authentication alone.

Six of the ten categories are fundamentally about authorization failures. As one way to put it: four of the top five risks are authentication and authorization issues. Anyone who wants to understand API security first has to understand why a valid request can produce a wrong answer. The underlying management of identities and permissions that all of these checks build on is covered in our article on Identity and Access Management (IAM).

The ten categories of the 2023 edition at a glance

#ID (2023)Name (2023)
1API1:2023Broken Object Level Authorization (BOLA)
2API2:2023Broken Authentication
3API3:2023Broken Object Property Level Authorization (BOPLA)
4API4:2023Unrestricted Resource Consumption
5API5:2023Broken Function Level Authorization (BFLA)
6API6:2023Unrestricted Access to Sensitive Business Flows
7API7:2023Server Side Request Forgery (SSRF)
8API8:2023Security Misconfiguration
9API9:2023Improper Inventory Management
10API10:2023Unsafe Consumption of APIs

Our example API

All code samples in this article belong to one small fictional REST API written in Node.js with the Express framework. It manages users, orders, and transactions. An authenticate middleware sets the object req.user (with id and role) when a token is valid, and a data-access layer called db wraps the database. This way you see every risk in the same context, first vulnerable, then hardened.

API1:2023 Broken Object Level Authorization (BOLA)

BOLA has been the undisputed number one since 2019 and stayed there in 2023. The flaw: the API accepts an object ID as input but never checks whether the requesting user is allowed to see or modify that specific object. An authenticated user simply changes an ID in the URL and gets someone else's data.

Conceptually, BOLA describes the same vulnerability family as IDOR (Insecure Direct Object References). OWASP merely shifted the focus from the attack mechanism (a manipulable reference) to the root cause (a missing authorization check). If you want to dig into the IDOR fundamentals, see our article on Broken Access Control and IDOR.

Vendor Salt Security estimates that BOLA plays a role in roughly 40 percent of all API attacks (a vendor figure without disclosed methodology, so treat it as an order of magnitude rather than a hard number). What makes BOLA so dangerous, as Snyk puts it well: no hacking tools required, just one changed digit, and because both request and response look legitimate, classic web application firewalls often miss it entirely.

Vulnerable: the endpoint returns any order by its ID without checking ownership.

app.get("/api/orders/:orderId", authenticate, async (req, res) => {
  const order = await db.orders.findById(req.params.orderId);
  res.json(order);
});

Secure: before returning, the code verifies that the object belongs to the requesting user.

app.get("/api/orders/:orderId", authenticate, async (req, res) => {
  const order = await db.orders.findById(req.params.orderId);
  if (!order) {
    return res.status(404).json({ error: "Not found" });
  }
  if (order.userId !== req.user.id) {
    return res.status(403).json({ error: "Access denied" });
  }
  res.json(order);
});

Real-world case: in the 2023 T-Mobile incident, attackers used a single API to access data on roughly 37 million customers, a textbook BOLA pattern. This incident contributed to a 31.5 million US dollar settlement that T-Mobile reached with the US regulator FCC in 2024. The frequently cited 350 million US dollar settlement belongs to a separate, non-API-specific breach from August 2021 that affected roughly 76.6 million people. The Peloton incident (2021) also falls into this category: swapping user IDs made other users' profile and workout data retrievable.

API2:2023 Broken Authentication

Number two in both the 2019 and the 2023 edition. This is not about what someone is allowed to do, but who they are: weaknesses in verifying identity. Typical patterns include missing rate limiting on login and token endpoints (an open door for brute-force attacks), JWTs accepted with {"alg":"none"}, expiry times that are never validated, tokens placed in URLs (which then end up in logs), and no re-authentication for sensitive actions. In 2019 the category was called "Broken User Authentication"; in 2023 it was generalized to cover machine-to-machine authentication as well.

A common and severe mistake: decoding the token without verifying its signature. That lets an attacker forge the payload at will.

Vulnerable: the token is only decoded, not verified.

const jwt = require("jsonwebtoken");

function authenticate(req, res, next) {
  const token = req.headers.authorization?.split(" ")[1];
  // Decodes the payload without verifying the signature
  req.user = jwt.decode(token);
  next();
}

Secure: the signature is verified, the allowed algorithm is pinned, and expiry is checked.

const jwt = require("jsonwebtoken");

function authenticate(req, res, next) {
  const token = req.headers.authorization?.split(" ")[1];
  if (!token) {
    return res.status(401).json({ error: "Missing token" });
  }
  try {
    // Verifies signature and expiry, pins the allowed algorithm
    req.user = jwt.verify(token, process.env.JWT_SECRET, {
      algorithms: ["HS256"]
    });
    next();
  } catch (err) {
    return res.status(401).json({ error: "Invalid token" });
  }
}

Login and token endpoints also need hard rate limits (see API4) so that brute-force attempts run into a wall, plus multi-factor authentication for sensitive accounts.

Real-world case: in the USPS data leak (2018), reporting found that any authenticated user could query account details through the API, affecting roughly 60 million accounts. In the 3Commas incident (2022), API key abuse led to a reported loss of around 22 million US dollars.

API3:2023 Broken Object Property Level Authorization (BOPLA)

BOPLA is the most important structural change of 2023. The category merges two earlier ones: API3:2019 Excessive Data Exposure and API6:2019 Mass Assignment. OWASP justifies this by pointing to their shared root cause, the missing or improper authorization check at the level of individual object properties. Where BOLA asks whether you may see the object, BOPLA asks whether you may read or write that single property.

BOPLA is best understood in two sub-forms.

Form 1: Excessive Data Exposure (returning too much)

The API returns more fields than the user should see, such as a password hash, an internal role, or a social security number. Hiding those fields in the frontend does not help: they are visible in the network inspector.

Vulnerable: the entire user object goes into the response.

app.get("/api/users/:id", authenticate, async (req, res) => {
  const user = await db.users.findById(req.params.id);
  // Returns the whole record, including passwordHash and internalRole
  res.json(user);
});

Secure: an explicit allow-list determines which fields are returned.

app.get("/api/users/:id", authenticate, async (req, res) => {
  const user = await db.users.findById(req.params.id);
  if (!user) {
    return res.status(404).json({ error: "Not found" });
  }
  res.json({
    id: user.id,
    name: user.name,
    email: user.email
  });
});

Form 2: Mass Assignment (letting too much in)

The reverse mistake: the API accepts fields from the request body without checking them. A user only means to change their name, but smuggles "role": "admin" into the payload and escalates their privileges.

Vulnerable: the entire request body is written to the database blindly.

app.patch("/api/users/:id", authenticate, async (req, res) => {
  // Copies every field from the request body without checking
  const updated = await db.users.update(req.params.id, req.body);
  res.json(updated);
});

Secure: only explicitly permitted fields are applied.

app.patch("/api/users/:id", authenticate, async (req, res) => {
  const allowed = ["name", "email"];
  const updates = {};
  for (const field of allowed) {
    if (field in req.body) {
      updates[field] = req.body[field];
    }
  }
  const updated = await db.users.update(req.params.id, updates);
  res.json(updated);
});

The rule for both forms: define explicit allow-lists for input and output, work with fixed response schemas, and never pass a raw request object straight into an ORM.

API4:2023 Unrestricted Resource Consumption

In 2019 this was "Lack of Resources & Rate Limiting"; in 2023 it was generalized. It is no longer only about classic request rate limiting, but about any form of unrestricted consumption: CPU, memory, storage, bandwidth, and expensive third-party calls. Without limits, an attacker can overwhelm the service or drive up operating costs.

Common triggers: no limit on compute-heavy operations (image processing, ML inference), no maximum payload sizes, unbounded list responses, and missing depth or complexity limits for GraphQL. One documented example: a financial API without pagination limits produced a 90-second database query for a particularly active account, slowing the service for everyone.

Vulnerable: the endpoint returns all transactions without any limit.

app.get("/api/transactions", authenticate, async (req, res) => {
  // Returns every transaction with no limit
  const transactions = await db.transactions.findAll({ userId: req.user.id });
  res.json(transactions);
});

Secure: a global rate limit plus an enforced pagination cap.

const rateLimit = require("express-rate-limit");

const apiLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  limit: 100 // 100 requests per IP and window (option "max" before v7)
});
app.use("/api/", apiLimiter);

app.get("/api/transactions", authenticate, async (req, res) => {
  const limit = Math.min(parseInt(req.query.limit, 10) || 50, 100);
  const offset = parseInt(req.query.offset, 10) || 0;
  const transactions = await db.transactions.findAll({
    userId: req.user.id,
    limit,
    offset
  });
  res.json(transactions);
});

API5:2023 Broken Function Level Authorization (BFLA)

BFLA has sat unchanged at number five since 2019. The distinction from BOLA is crucial: BOLA is about someone else's data (a foreign object), BFLA is about someone else's function or action (for example an admin delete function called by a regular user). APIs often check authentication (is the token valid?) but not authorization (does this user hold the right role?).

A typical attack looks like this:

DELETE /api/admin/users/8827
Authorization: Bearer <token_of_a_regular_user>

If there is no server-side role check, the deletion succeeds despite a token that is merely valid, not privileged.

Vulnerable: the admin endpoint only checks that someone is logged in.

app.delete("/api/admin/users/:id", authenticate, async (req, res) => {
  await db.users.delete(req.params.id);
  res.json({ deleted: true });
});

Secure: a reusable role middleware enforces the required permission.

function requireRole(role) {
  return (req, res, next) => {
    if (req.user.role !== role) {
      return res.status(403).json({ error: "Forbidden" });
    }
    next();
  };
}

app.delete(
  "/api/admin/users/:id",
  authenticate,
  requireRole("admin"),
  async (req, res) => {
    await db.users.delete(req.params.id);
    res.json({ deleted: true });
  }
);

As a rule, administrative functions should be separated from regular user actions and protected by role-based access control (RBAC), ideally following the principle of least privilege.

API6:2023 Unrestricted Access to Sensitive Business Flows

One of the new 2023 categories and conceptually the most demanding. There is no technical bug in the classic sense: the API works exactly as designed. The problem is that a sensitive business flow is exposed without protection against automated, large-scale abuse. As ApyGuard puts it pointedly: attackers use the API faster and at a larger scale than any legitimate user ever would.

Typical abuse patterns:

  • Inventory hoarding: bots repeatedly hit the purchase endpoint during a product drop and buy up the entire stock.
  • Referral fraud: automated account creation claims welcome bonuses thousands of times over.
  • Ticket and appointment abuse: scripts block every slot faster than humans can. A common illustration is scalping bots that buy up the bulk of concert tickets, forcing legitimate customers to inflated prices.

The defense is not a single fix but a combination: per-user velocity limits, bot detection, device fingerprinting, behavioral analysis, and, where needed, CAPTCHA or proof-of-work challenges.

Vulnerable: the checkout endpoint has no abuse protection whatsoever.

// createOrder stands for the order logic of our example API
app.post("/api/checkout", authenticate, async (req, res) => {
  const order = await createOrder(req.user.id, req.body.items);
  res.json(order);
});

Secure: a per-user velocity limit and an anti-bot check run in front of it.

const rateLimit = require("express-rate-limit");

// Limits checkouts per authenticated user, not just per IP
const purchaseVelocityLimit = rateLimit({
  windowMs: 60 * 1000,
  limit: 5,
  keyGenerator: (req) => req.user.id
});

// verifyHumanChallenge stands for an anti-bot middleware
// (CAPTCHA or proof-of-work), typically provided by a dedicated service
app.post(
  "/api/checkout",
  authenticate,
  purchaseVelocityLimit,
  verifyHumanChallenge,
  async (req, res) => {
    const order = await createOrder(req.user.id, req.body.items);
    res.json(order);
  }
);

API7:2023 Server Side Request Forgery (SSRF)

Also new in 2023 as its own top-10 category. SSRF occurs when an API takes a URL as input and fetches it server-side without validating the target. Attackers use this to reach internal services or, most dangerously, cloud metadata endpoints such as 169.254.169.254, which in many environments exposes IAM credentials. Veracode cites the spread of microservices and cloud architectures as the reason SSRF gained importance.

A typical attack attempt:

POST /api/import
{"source_url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}

Vulnerable: the API fetches any URL the client supplies.

const axios = require("axios");

app.post("/api/import", authenticate, async (req, res) => {
  // Fetches whatever URL the client supplies
  const response = await axios.get(req.body.sourceUrl);
  res.json(response.data);
});

Secure: scheme and host are checked against an allow-list, and private, loopback, and link-local IPv4 ranges are blocked on top of that.

const axios = require("axios");
const dns = require("dns").promises;

const ALLOWED_HOSTS = ["files.example.com", "cdn.example.com"];

function isPrivateIp(ip) {
  return (
    ip.startsWith("10.") ||
    ip.startsWith("127.") ||
    ip.startsWith("192.168.") ||
    ip.startsWith("169.254.") ||
    /^172\.(1[6-9]|2\d|3[01])\./.test(ip)
  );
}

app.post("/api/import", authenticate, async (req, res) => {
  let target;
  try {
    target = new URL(req.body.sourceUrl);
  } catch (err) {
    return res.status(400).json({ error: "Invalid URL" });
  }
  if (target.protocol !== "https:" || !ALLOWED_HOSTS.includes(target.hostname)) {
    return res.status(400).json({ error: "URL not allowed" });
  }
  const { address } = await dns.lookup(target.hostname);
  if (isPrivateIp(address)) {
    return res.status(400).json({ error: "Blocked target" });
  }
  // maxRedirects: 0 keeps an allowed host from redirecting to an internal target
  const response = await axios.get(target.toString(), { maxRedirects: 0 });
  res.json(response.data);
});

One important caveat: the IP check in this example is only defense in depth on top of the host allow-list, not the primary safeguard. A production-grade SSRF defense additionally has to cover IPv6 ranges (such as ::1 and fc00::/7) and DNS rebinding (the host may resolve to a different IP between the check and the actual request). Vetted libraries such as ssrf-req-filter handle these cases.

Real-world case: the 2019 Capital One breach is the textbook example: an SSRF vulnerability allowed an attacker to query AWS metadata, extract IAM credentials, and reach S3 buckets holding roughly 100 million customer records. The Shopify incident (2020), an SSRF via a screenshot feature, also belongs in this category.

API8:2023 Security Misconfiguration

The name is unchanged since 2019, but the category moved up one slot (from API7:2019 to API8:2023) when Injection was dropped. It is the broad catch-all for misconfigured security parameters: overly permissive CORS headers, open debug endpoints, default credentials, missing transport encryption, verbose error messages with stack traces, and unnecessarily enabled HTTP methods. The particularly insidious CORS pattern is origin reflection with credentials: the server echoes the Origin header of every incoming request back in Access-Control-Allow-Origin while also setting Access-Control-Allow-Credentials: true. Any attacker-controlled website can then make authenticated requests on the victim's behalf and read the responses. The naive combination of a wildcard (Access-Control-Allow-Origin: *) with credentials is rejected by browsers per the Fetch specification, which is exactly why developers often fall back to origin reflection, the pattern that is genuinely dangerous.

Vulnerable: origin reflection with credentials and an open debug endpoint that leaks environment variables.

const cors = require("cors");

app.use(cors({
  origin: true, // reflects any request origin back
  credentials: true // and allows credentials at the same time: exploitable from any website
}));

app.get("/debug", (req, res) => {
  res.json({ env: process.env });
});

Secure: a restrictive CORS configuration, security headers via Helmet, no debug endpoint, and an error handler that does not leak stack traces.

const cors = require("cors");
const helmet = require("helmet");

app.use(helmet());
app.use(cors({
  origin: ["https://app.example.com"],
  credentials: true
}));

// No debug endpoints in production, remove the x-powered-by header
app.disable("x-powered-by");

app.use((err, req, res, next) => {
  // Do not leak stack traces to the client
  console.error(err);
  res.status(500).json({ error: "Internal server error" });
});

Real-world case: in the SVR Tracking incident (2017), a misconfigured, publicly accessible AWS S3 bucket exposed roughly 540,000 accounts of the vehicle tracking service, including customer logins and vehicle data. Strictly speaking the flaw sat in the storage layer rather than in the API itself, but the root cause is exactly what this category targets: a security-relevant configuration left wide open.

API9:2023 Improper Inventory Management

In 2019 this was "Improper Assets Management"; in 2023 it was renamed with a focus on a complete, current inventory of all API elements: hosts, environments, versions, documentation. The key term is the shadow API: an undocumented, forgotten, or unmanaged endpoint outside the official inventory. Sources of such shadow APIs include old versions still running alongside current ones with fewer controls, undocumented developer routes, and internet-reachable staging environments holding production-like data.

Vulnerable: an old v1 route stays online after the v2 launch, unauthenticated and undocumented.

// Legacy endpoint left online after the v2 launch, no auth and undocumented
app.get("/api/v1/users/:id/export", async (req, res) => {
  const user = await db.users.findById(req.params.id);
  res.json(user);
});

Secure: the outdated version is formally retired, with a Sunset header and a clear status response.

// v1 is officially deprecated: authenticated and with a sunset date
app.get("/api/v1/users/:id/export", authenticate, (req, res) => {
  res.set("Sunset", "Sat, 31 Jan 2026 23:59:59 GMT");
  res.status(410).json({ error: "This API version has been retired" });
});

In practice this requires continuous API discovery, well-maintained OpenAPI documentation, clear versioning and deprecation strategies, and monitoring for newly appearing, unrecorded endpoints.

API10:2023 Unsafe Consumption of APIs

The second entirely new category of 2023. It replaces the former "Insufficient Logging & Monitoring" and flips the perspective: it is not your API that gets attacked, it is your application that blindly trusts the responses of a third-party API. Developers often treat external API data as more trustworthy than direct user input, and that is exactly the mistake. If the partner is compromised or delivers manipulated data, your infrastructure processes the payload without checking it.

An illustrative scenario (after ApyGuard): a geolocation provider's database is poisoned with SQL injection strings in city names. Your application inserts the delivered city name straight into a query and thereby executes foreign code.

Vulnerable: the third party's response goes unchecked into a SQL query.

const axios = require("axios");

app.get("/api/city-info", authenticate, async (req, res) => {
  const geo = await axios.get(`https://geoprovider.example.com/lookup?ip=${req.ip}`);
  // Trusts the third-party field and interpolates it straight into SQL
  const rows = await db.raw(
    `SELECT * FROM cities WHERE name = '${geo.data.city}'`
  );
  res.json(rows);
});

Secure: the external response is validated and used only in a parameterized form.

const axios = require("axios");

app.get("/api/city-info", authenticate, async (req, res) => {
  const geo = await axios.get(`https://geoprovider.example.com/lookup?ip=${req.ip}`);
  const city = String(geo.data.city || "").slice(0, 100);
  if (!/^[\p{L}\s.'-]+$/u.test(city)) {
    return res.status(422).json({ error: "Unexpected provider response" });
  }
  // Parameterized query, the third-party value is treated as untrusted input
  const rows = await db.raw("SELECT * FROM cities WHERE name = ?", [city]);
  res.json(rows);
});

Treat every response from an external API as untrusted input: validate, sanitize, parameterize. How dangerous unfiltered values are in database queries is shown in our article on the basics of SQL injection.

What changed from 2019 to 2023

The 2023 edition is not a simple reissue but a structural rework based on four additional years of breach and bug-bounty data. The key changes:

  • Merge into BOPLA (API3:2023): API3:2019 "Excessive Data Exposure" and API6:2019 "Mass Assignment" became one category focused on their shared root cause (authorization at the property level).
  • Three new categories: API6:2023 "Unrestricted Access to Sensitive Business Flows", API7:2023 "Server Side Request Forgery", and API10:2023 "Unsafe Consumption of APIs".
  • Renames with the core preserved: API2:2019 "Broken User Authentication" became "Broken Authentication", API4:2019 "Lack of Resources & Rate Limiting" became "Unrestricted Resource Consumption", API9:2019 "Improper Assets Management" became "Improper Inventory Management".
  • Dropped as a standalone category: API8:2019 "Injection" is no longer a separate top-10 category in 2023 (the risk persists but is no longer listed separately). API10:2019 "Insufficient Logging & Monitoring" was replaced by "Unsafe Consumption of APIs".
  • Unchanged in both ID and name: API1 (BOLA) and API5 (BFLA). Security Misconfiguration kept its name but moved from API7:2019 to API8:2023 when Injection was dropped. API2 kept position two but was slightly renamed, as noted above.

The absence of Injection as its own category is not uncontroversial. Injection risks remain critical even though they are no longer listed separately. Veracode speculates about the reason (explicitly as an opinion, not an official OWASP rationale) that newer frameworks bring built-in protection. In practice, injection vulnerabilities stay relevant; in 2023 they simply surface elsewhere, for example as a consequence of Unsafe Consumption (API10).

Current threat landscape 2023 to 2025

One reason many overviews of this topic feel dated: they cite almost exclusively cases from 2017 to 2021. The threat landscape has intensified since then. Vendor Wallarm's annual API ThreatStats report provides current figures (a vendor analysis, so read them with the corresponding caveat):

  • More than 50 percent of the vulnerabilities in the CISA KEV catalog (the list of actually exploited vulnerabilities maintained by the US agency CISA) were API-related in 2024, compared with roughly 20 percent in 2023. The population is the public KEV catalog; the analysis is Wallarm's.
  • Five large 2024 breaches, all classified as access-control or authentication flaws: Dell (around 49 million users), Twilio (around 33.4 million linked phone numbers), Internet Archive (around 31 million users), Trello (around 15 million users), and an Optus entry.

The Optus incident needs some context: it is a single incident from September 2022 in which an unprotected, exposed API served as the access path. Initial reporting spoke of roughly 9.8 million affected people, while the Australian privacy regulator OAIC bases its civil penalty proceedings (2025) on roughly 9.5 million. Wallarm's "2024" dating refers to the entry's inclusion in the report, not the year of the incident, and the 11.2 million figure from Impart.ai deviates from all primary sources. The defensible range is therefore 9.5 million (OAIC) to 9.8 million (initial reporting), and the incident year is unambiguously 2022.

In its report, Wallarm maps breaches to its own nomenclature, aligned with but not identical to OWASP (for example "Broken Access Control"), not to the official OWASP 2023 numbering. We therefore map the cases back to the corresponding OWASP categories rather than mixing vendor labels with the official ones.

API security is now AI security too

A point most overviews miss: modern AI integrations are, at their core, API applications. Chatbots, agents, and tools connected through the Model Context Protocol (MCP) communicate over HTTP-based API interfaces; MCP itself speaks JSON-RPC 2.0, not REST. Certification body GUTcert stresses the same underlying point: MCP integrations are API endpoints, which makes API security a prerequisite for secure AI implementations. We examine the protocol and its attack surface in detail in our article on MCP security.

Wallarm backs this up with numbers: of 439 tracked AI-related vulnerabilities (CVEs) in 2024, an increase of 1,025 percent over 2023, it reports that 98.9 percent are API-related (again a vendor-own analysis). Anyone securing an AI application cannot avoid the OWASP API Security Top 10. How the specific AI attacks compare alongside this is something we cover in our article on the basics of prompt injection.

Regulatory context

For organizations that need a structured basis, two anchors are worth noting. First, CWE coverage: according to GUTcert, the OWASP API Security Top 10 references roughly 24 CWEs directly and 128 CWEs indirectly, which corresponds to more than 10 percent of the entire CWE catalog (a GUTcert figure, verifiable against the official CWE catalog). That makes the list a structured audit grid, not just a loose collection of topics.

Second, in the German-speaking region the BSI technical guideline TR-03161 requires, according to GUTcert, a separate assessment of the client side and the server side during security reviews. For regulated sectors (healthcare, critical infrastructure) that is a concrete methodological anchor. It fits into the broader picture of obligations set by frameworks such as the NIS2 directive.

FAQ

What is the OWASP API Security Top 10?

The OWASP API Security Top 10 is the authoritative reference list for the most critical security risks specific to APIs, maintained by the community-driven OWASP API Security Project. The current version is the 2023 edition, a ground-up rework of the original 2019 list. It exists because the general OWASP Top 10 for web applications does not fully capture the vulnerability patterns typical of APIs. Six of the ten categories are fundamentally about authorization failures.

What is the difference between BOLA and BFLA?

BOLA (API1:2023, Broken Object Level Authorization) is about someone else's data: the API never checks whether the requesting user may see or modify the specific object, such as an order with a given ID. BFLA (API5:2023, Broken Function Level Authorization) is about someone else's function: a regular user invokes an action reserved for another role, for example an admin delete endpoint. In short, BOLA is the wrong object, BFLA is the wrong function.

What changed between the OWASP API Top 10 2019 and 2023?

Three categories are new in 2023: Unrestricted Access to Sensitive Business Flows, Server Side Request Forgery, and Unsafe Consumption of APIs. Excessive Data Exposure and Mass Assignment were merged into BOPLA (API3:2023). Injection (API8:2019) is no longer a standalone category, which moved Security Misconfiguration up from API7:2019 to API8:2023. Insufficient Logging & Monitoring (API10:2019) was replaced by Unsafe Consumption of APIs. BOLA (API1) and BFLA (API5) kept both their IDs and their names.

What is the most common API vulnerability?

BOLA (Broken Object Level Authorization) has been the undisputed number one on the list since 2019. Vendor Salt Security estimates that BOLA plays a role in roughly 40 percent of all API attacks (a vendor figure without disclosed methodology). What makes BOLA so dangerous is that it requires no hacking tools: one changed ID in the URL is enough, and because both request and response look legitimate, classic web application firewalls often miss it entirely.

How do I secure a REST API?

Check every endpoint against the authorization questions behind the Top 10: may this user see this object (BOLA), read or write this property (BOPLA), invoke this function (BFLA)? On top of that, verify token signatures with a pinned algorithm, enforce hard rate limits and pagination caps, configure CORS restrictively alongside security headers, maintain a complete API inventory without forgotten legacy versions, and treat every response from an external API as untrusted input.

Conclusion

The OWASP API Security Top 10 (2023) shifts the focus away from classic technical exploits toward authorization: the most dangerous API attacks consist of perfectly valid requests that simply receive the wrong answer. Six of the ten categories, and four of the top five, revolve around authorization and authentication failures.

Taking the list seriously means checking every endpoint against four questions: may this user see this object (BOLA)? May they read or write this property (BOPLA)? May they invoke this function (BFLA)? And are resource consumption, the business flow, and every external data source properly limited and validated? The continuous example API in this article shows the difference between vulnerable and secure code for each of those questions. Precisely this shift in perspective, from "does the request run?" to "is it allowed to?", is the heart of modern API security.