OWASP (Open Worldwide Application Security Project) publishes the OWASP Top 10, an awareness document for common web-application risk classes. It is a baseline for threat modeling and verification, not proof that an application is secure. The current released list is the 2025 edition.

OWASP Top 10 (2025)

A01: Broken Access Control

The system accepts an operation the caller is not allowed to perform. A signed-in user changes /invoices/42 to /invoices/43 and reads another tenant’s data because the endpoint checked identity but not ownership. Authorize every resource and action server-side, deny by default, and test nearby denied cases.

var decision = await authorizationService.AuthorizeAsync(
    User,
    invoice,
    "CanReadInvoice");
 
if (!decision.Succeeded)
    return Forbid();

A02: Security Misconfiguration

Unsafe defaults, unnecessary services, permissive cloud policies, missing headers, or detailed production errors expose a path the application did not intend. Build hardened configuration into deployment, compare it continuously with policy, and fail closed when required settings are absent.

A03: Software Supply Chain Failures

A compromised package, build action, registry, or signing identity reaches production through a trusted delivery path. Maintain an inventory, restrict and pin build inputs, verify provenance where available, isolate CI credentials, and practice replacing a compromised dependency without disabling the evidence trail.

A04: Cryptographic Failures

Sensitive data is exposed because protection is absent or the primitive, parameters, nonce, key, or trust model is wrong. Plain SHA-256 password hashes and a reused AES-GCM nonce are different failures with the same root: cryptography was applied outside its required construction. Use approved libraries, password-storage schemes, authenticated encryption, and managed key lifecycles.

A05: Injection

Untrusted data changes the syntax of a SQL, shell, template, LDAP, or another interpreter command. A query built by concatenating an email address lets input become SQL. Keep code and data separate with parameterized APIs, allowlist identifiers that cannot be parameters, and constrain any interpreter the process can reach.

var user = await connection.QueryFirstOrDefaultAsync<User>(
    "SELECT * FROM Users WHERE Email = @Email",
    new { Email = userEmail });

A06: Insecure Design

The intended workflow lacks a control, so correct implementation still produces an exploitable system. A password-reset token with no expiry, attempt budget, or account binding is not repaired by clean code. Threat-model abuse cases and make rate, value, state transition, and recovery invariants explicit before implementation.

A07: Authentication Failures

Credential, session, recovery, or authenticator handling lets an attacker assume another identity. Defend against credential stuffing, protect session and renewal tokens, require phishing-resistant authentication where the risk warrants it, and make account recovery at least as strong as normal sign-in.

A08: Software or Data Integrity Failures

The system trusts code, serialized state, updates, or business data without establishing its origin and integrity. Verify signed artifacts and update metadata, constrain deserialization to expected types and schemas, and keep the verification key outside the channel that delivers the payload.

A09: Security Logging and Alerting Failures

The system cannot reconstruct or detect an attack because decision events are absent, unsafe, or never turned into alerts. Record authentication, authorization, administrative, and sensitive-data events with safe metadata. Test that a real abuse sequence triggers a routed alert; collecting logs alone is not detection.

A10: Mishandling of Exceptional Conditions

Unexpected states, timeouts, resource exhaustion, partial failure, or exception paths leave the system open or inconsistent. A payment handler that commits an order after its authorization service times out fails open. Define failure semantics, bound resources, make retries idempotent, and test recovery from faults at every external boundary.

API Threats and Controls

For an API, apply the same Top 10 categories at the object, property, and function levels. A valid token does not prove that the caller may read object 42, set its isAdmin property, or invoke an administrative operation. Load the exact resource, authorize each action, bind writable schemas, reject unknown fields, parameterize interpreter inputs, and bound payload size, concurrency, and workflow retries.

Pair preventive controls with evidence: denied cross-tenant identifiers for access control, validation-failure rates for malformed input, inventory drift for shadow endpoints, and cost or queue-depth anomalies for resource abuse. Do not log tokens, passwords, API keys, card data, or request bodies to obtain that evidence. Basic authentication, JWT, OAuth, and OpenID Connect also remain different protocol roles; changing token format does not repair a missing authorization or trust check.

Pitfalls

Checklist Security (False Sense of Compliance)

What goes wrong: a team marks each broad risk class “done” and treats the result as proof of security, even though the list cannot identify this application’s assets, trust boundaries, business rules, or chained abuse cases.

Mitigation: use the Top 10 to seed threat models and verification. Add architecture-specific abuse cases, security review, dependency monitoring, runtime testing, and penetration testing according to the system’s exposure and release risk.

Questions

References