Est.
FeaturesLong read

REST API Security Checks Before You Go to Production

Use OWASP's API Security Top 10 to audit your endpoints before shipping to production.

Senior Writer · · 10 min read · Updated
Cover illustration for “REST API Security Checks Before You Go to Production”
Features · August 11, 2026 · 10 min read · 2,324 words

The OWASP API Security Top 10 is the closest thing the industry has to a consensus map of where attacks actually land. First published in 2019 and updated in 2023, it was developed by a global community of security practitioners who analyzed real breach data, bug bounty reports, and vulnerability disclosures to identify the patterns that cause the most harm in production API environments. Unlike theoretical frameworks built on assumptions about attacker behavior, the Top 10 reflects what actually gets exploited. The 2023 edition added new categories to reflect a shift in how APIs are used: they no longer just expose data, they also consume external services, and both directions introduce risk. Understanding the Top 10 as an organizing framework rather than a one-time checklist is the right way to approach it.

Here are the categories that drive everything below:

  • Broken Object Level Authorization (BOLA). Top of the list since 2019. An endpoint returns a resource without checking whether the requester owns it. Simple to exploit and consistently underestimated.

  • Broken Authentication. Stolen tokens, credential stuffing, brute force. Valid authentication does not mean authorization is enforced. These are genuinely different things, and conflating them is a common mistake.

  • Broken Object Property Level Authorization (BOPLA). New framing in 2023, merging Excessive Data Exposure and Mass Assignment. The root cause in both cases is that nobody checked what the response was actually returning.

  • Unrestricted Resource Consumption. No request limits means you are one patient attacker away from a denial-of-service situation, and a brute-force machine for anyone willing to hammer an authentication endpoint.

  • Broken Function Level Authorization (BFLA). Admin-only functions reachable by standard users because cross-role testing never happened.

  • Security Misconfiguration. Gateways and infrastructure are complex and get misconfigured quietly, often without anyone noticing until it matters.

  • Improper Inventory Management. Unknown and abandoned endpoints represent a real attack surface category, as well as a documentation problem.

  • Server-Side Request Forgery (SSRF). New in 2023. An API that fetches remote resources without validating the URI can be pointed at internal systems that were never intended to be exposed.

Authentication: What "Secure Login" Still Gets Wrong at the API Layer

Most API attacks come from authenticated sessions. The attacker logged in, obtained a token, and is now doing things they should not be allowed to do while the system treats it as normal traffic. Authentication is a necessary condition, but getting it right does not mean the rest holds.

Protocol choices:

  • OAuth 2.0 for user-facing APIs. It supports delegated authorization without passing passwords around and is the right default for most REST APIs.

  • Mutual TLS (mTLS) for service-to-service communication. Certificate-based authentication is significantly harder to spoof than a shared secret.

Token hygiene is where implementations get sloppy in practice, often because teams are racing a deadline:

  • Access tokens should be short-lived, ranging from minutes to an hour depending on sensitivity. If a token is intercepted, a short expiry limits the exposure window.

  • Long-lived refresh tokens belong in a separate flow. They maintain sessions without extending the risk window of the access token itself.

  • For web applications, store tokens in secure, httpOnly cookies. The localStorage API is accessible to any JavaScript on the page, including injected scripts.

Before launch, scan for any endpoint that skips token validation, including internal-only routes. "Internal" describes a network topology assumption, not a security boundary. Also verify that token expiry is enforced server-side. Client-side expiry checks are advisory at best, because an attacker controls the client.

Authorization: Why a Passing Auth Check Doesn't Mean the Right User Can Reach the Right Data

Authentication answers "who are you?" Authorization answers "are you allowed to do this specific thing to this specific resource?" These are separate questions, and a lot of APIs only address the first one.

BOLA in practice. An endpoint accepts a resource ID in the URL and returns the resource. It checks that the user is logged in but does not check whether this user owns that resource. Authenticated User A requests /invoices/1042, which belongs to User B, and gets it back. That is BOLA. It is the most common exploitable pattern in production APIs, and it is frequently one request away from working. For every endpoint that accepts an object ID, verify server-side that the requesting user has rights to that specific object. Never trust the client to only send IDs it owns.

BFLA in practice. Admin-only functions like delete, promote, and bulk-export are reachable by lower-privilege users because function-level authorization was skipped. Catching this requires deliberate cross-role testing. Enumerate all endpoints by HTTP method, map each to the minimum required role, then log in as a standard user and call every endpoint flagged as admin-only. Do this in your test environment and again in production before launch.

BOPLA is subtler. Even when a user legitimately accesses a resource, the response might include internal flags, other users' data, or admin metadata alongside the fields they were supposed to see. Also worth checking: a route guard that passes does not mean every HTTP method on that route is safe. A user who can GET a resource cannot automatically PUT or DELETE it. And authorization logic that works correctly inside your own API does not automatically carry through to external API calls made on behalf of users. Audit those flows independently.

Transport Security: The Configurations That Determine Whether Your Encryption Actually Holds

TLS encrypts data in transit. Without it, credentials, tokens, and payloads are readable to anyone on the path between client and server. A meaningful share of customer-facing APIs still run without basic encryption in production.

Version specifics:

  • TLS 1.3 is preferred.

  • TLS 1.2 is the minimum acceptable floor.

  • SSL 3.0, TLS 1.0, and TLS 1.1 must be explicitly disabled at the server or gateway level, not merely discouraged, because otherwise they can be negotiated down to.

Enforce HTTPS everywhere with no HTTP fallback. Handle the redirect at the infrastructure level, not in application code. If it is handled in code, someone will find the HTTP endpoint directly and bypass the redirect entirely.

The check that trips up developers most often is certificate validation being quietly disabled in the codebase. verify=False in Python's requests library and rejectUnauthorized: false in Node.js both get set during development because dealing with self-signed certificates locally is annoying, and both get left in when the code ships. In production, disabling certificate validation means TLS provides encryption without identity verification. You are encrypting a connection without confirming who is on the other end. Run a TLS configuration scan against every public-facing endpoint before launch. testssl.sh and SSL Labs both do this well and are free.

Input Validation: The Oldest Vulnerability Class That APIs Keep Reintroducing

Injection attacks have been on every security list for decades. APIs keep reintroducing them by treating input as trusted. The job is to treat all incoming data as untrusted until it has been explicitly validated against a defined schema.

Content-Type enforcement is a reasonable starting point. If the API expects JSON, reject any request that does not declare Content-Type: application/json and return 415 Unsupported Media Type rather than attempting to process unexpected formats. This prevents unexpected parsers from running on input the application was never designed to handle.

Schema validation via OpenAPI or Swagger:

  • Define allowed field names, types, lengths, and formats in the spec.

  • Use an API gateway or validation middleware to reject non-conforming requests before they reach application logic.

  • A malformed payload stopped at the gateway never touches your code.

Test with deliberately malformed payloads: oversized strings, wrong field types, extra fields not in the spec. Confirm the API rejects them cleanly. For database interactions, use parameterized queries consistently. Never interpolate user-supplied values into a query string.

For any endpoint that fetches a remote resource based on a user-supplied URL, validate that URI against an allowlist of expected domains and schemes. Reject anything targeting internal IP ranges, localhost, or link-local addresses. An API that fetches arbitrary URLs can be redirected at your internal metadata service, your database host, or anything else reachable from inside your network.

Rate Limiting and Resource Controls: How Uncapped APIs Become Denial-of-Service Targets

DDoS is one of the most common API attack vectors, and brute-force attacks on authentication endpoints follow closely behind. Both rely on the same precondition: no request limits.

Rate limiting and throttling are different tools. Rate limiting sets a hard cap on requests per time window. Throttling degrades service gradually for excess traffic. Hard limits stop volume attacks. Throttling protects legitimate users from being caught in the blast radius of nearby abuse.

Where to apply limits:

  • Authentication endpoints first, since these are the primary brute-force targets.

  • Resource-intensive endpoints including search, aggregation, and bulk export.

  • Per-user and per-IP, not just globally. A global limit can be distributed across many clients and bypassed entirely, which is a standard evasion pattern, not a corner case.

Set an explicit maximum request body size. For public APIs, a cap in the low-megabyte range is a reasonable starting point. Set hard timeouts on backend calls, database queries, and external API requests. An uncapped query or upstream call can hold connections open indefinitely, and enough of those will bring down a service without anything resembling a formal attack.

The 2023 OWASP list added Unrestricted Access to Sensitive Business Flows as its own category. Beyond raw request limits, check whether automated use of legitimate endpoints can cause business harm. Ticket purchase flows, comment posting, and account creation are all legitimate endpoints that become attack vectors when used at machine speed. Add compensating controls where the risk justifies it. Verify that rate limit headers come back in responses so legitimate clients can back off gracefully, and confirm that limit-exceeded responses return 429 rather than a 200 with an error body.

Error Handling and Information Leakage: What Your API Reveals When Something Goes Wrong

Verbose error responses are a reconnaissance tool. Stack traces, library version strings, database query fragments, and internal file paths help an attacker map your system without doing anything that looks like an attack. They break something intentionally and read what falls out.

Keep two layers strictly separate. For client-facing responses, return a generic, human-readable error message with a stable error code: enough for a legitimate developer to understand what went wrong, nothing useful about what is running underneath. For internal logging, capture the full error with stack trace and context. That detail lives in your logging system and does not go in the response body.

Walk through every error condition you can trigger: invalid input, missing auth, not-found, server errors. Inspect the raw response body each time and look for anything that reveals an internal path, library name, query fragment, or version string. Then search the codebase for debug flags or verbose error modes that were enabled during development and never turned off. They ship more often than teams expect. Use standard HTTP status codes consistently. Unusual response patterns get fingerprinted by automated scanners, and a consistent, predictable set of codes makes your API harder to profile.

Secrets Management: The Credentials That End Up in Repositories and Shared Workspaces

A significant number of organizations have secrets sitting in public repositories, usually through committed configuration files or transitive dependencies. This happens at companies with sophisticated engineering teams, and discovery typically comes from outside the organization.

Postman workspaces deserve a specific mention. API keys and live tokens saved in request collections and shared without access controls have been found publicly accessible at scale with real production credentials intact. If your team uses Postman, check what is in shared workspaces before launch.

Pre-production checklist:

  • Scan the full Git history for committed secrets, not just the current HEAD. Tools like truffleHog and git-secrets automate this.

  • Use environment variables or a dedicated secrets manager for all credentials. No hardcoded values in source.

  • Maintain separate, non-overlapping secrets for development, staging, and production. A compromise in a lower environment should not unlock production.

  • Rotate credentials on a schedule: database passwords, API keys, and service tokens. Automated rotation limits the damage window when something leaks quietly.

  • Manage encryption keys through a cloud provider key management service or a hardware security module.

Shadow and Zombie APIs: The Endpoints That Aren't in the Docs but Are Still Receiving Traffic

Shadow APIs were never in the official inventory. They exist, they receive traffic, and the organization does not know they are there. They show up through undocumented internal routes, legacy code paths, or APIs surfaced by third-party dependencies. Zombie APIs were once documented and actively used, then abandoned without being decommissioned. They are still technically reachable but no longer maintained or monitored.

The Stripe legacy endpoint case illustrates the risk clearly. Attackers exploited a deprecated endpoint that remained accessible but lacked the fraud detection and rate limiting of current endpoints. The endpoint predated those controls and never got updated because it was marked deprecated. It was still reachable, and that gap was the attack. Deprecated does not mean gone.

Before launch:

  • Generate a complete inventory of all reachable endpoints by crawling the application, scanning gateway logs, and inspecting routing configuration. Do not rely on documentation alone. The actual running system may differ from what was planned.

  • Compare that inventory against your official API spec. Everything in the traffic logs that is not in the spec is a shadow endpoint. Investigate it and disable it if there is no legitimate reason for it to exist.

  • For every endpoint in the official spec, verify it is actively maintained and subject to the same security controls as everything else. If it is deprecated, decommission it properly. Return 410 Gone and stop accepting traffic.

  • Add API discovery to your ongoing process. Shadow and zombie APIs emerge continuously as products evolve, so a one-time audit only reflects the current moment.

The gap between what engineering believes the attack surface is and what it actually is represents the core problem. Closing it requires visibility into what is running and accepting requests right now, not what was planned or what got documented.

Sources

  1. api7.ai
  2. cybelangel.com

More in Features