Row one of an OWASP Top 10 review is access control: sign in as user A, request user B’s record by its id, and record what comes back. That is how to test OWASP Top 10 vulnerabilities on a small app: 10 rows, one falsifiable test each, the evidence, and a reason for any row that does not apply.

How to test OWASP Top 10 vulnerabilities: the review in one table

An OWASP Top 10 review of a small web app is 10 rows: for each category, one or two tests a person can run and fail, the pass condition, the evidence kept, and either a result or a written reason the category does not apply. Two ordinary accounts and one admin account are enough to run it.

This review is one control in web app security: one step of a web application security audit, and a shared vocabulary for the controls in the application security checklist. Reviewing the application against the OWASP Top 10 and recording findings, fixes and evidence by category is deliverable 3.7 of the Production Hardening Sprint.

The rows follow the OWASP Top 10:2025 list in its published order. That order also answers which category is the most severe: the edition’s introduction says A01 Broken Access Control “maintains its position at #1 as the most serious application security risk”. Each row tests one class of OWASP Top 10 vulnerabilities, not one bug.

Category (2025)The testPass conditionEvidence to keepApplies?Go deeper (testing guide)Where the fix lives
A01 Broken Access ControlAs user A, request user B’s record by id; call an admin action as a member; call each API route with no sessionRefused every time, in whatever shape the stack refusesThe request, what came back, both account ids, the dateAlways, for any app with accountsWSTG-ATHZ-04 Testing for Insecure Direct Object ReferencesAuthorization rules
A02 Security MisconfigurationOn the production build, force an error and read it; read the response headers; look for default accounts, public buckets, debug modeNo stack trace, headers set, nothing public that should be privateHeader dump, the error response, a settings screenshotAlwaysWSTG-CONF-02 Test Application Platform ConfigurationHeaders and platform defaults
A03 Software Supply Chain FailuresRun the package manager’s audit from the committed lockfile; check the framework version against its advisoriesNo reachable advisory left without a fix plan; CI installs from the lockfileThe audit output, the framework version, the advisory checkedAlwaysNo dedicated test; nearest is WSTG-INFO-08 Fingerprint Web Application FrameworkDependency audit
A04 Cryptographic FailuresThe six checks in the cryptographic section belowAll six passHeader output, the password column’s format, search resultsAlways, if the app stores passwords, personal data or keysWSTG-CRYP-04 Testing for Weak EncryptionEncryption and password hashing
A05 InjectionSearch for string-built queries and raw HTML rendering; send a single quote and a harmless tag through each inputNo database error; the tag shows as plain textThe search results, the responsesAlways, if the app takes inputWSTG-INPV-05 Testing for SQL InjectionQuery building and output escaping
A06 Insecure DesignCan the client set a price or plan; can a coupon be replayed; can step three come first; is the costliest action limitedEach answer proven with a requestA one-page threat model with the answersAlwaysWSTG-BUSL-06 Testing for the Circumvention of Work FlowsThreat model and limits
A07 Authentication FailuresKnown and unknown email on login and reset; repeated wrong passwords; a reset link used twice; the old session after a password changeSame response for both emails; attempts throttled; link single-useThe responses side by sideUnless a managed provider runs every flow; then record its settingsWSTG-ATHN-03 Testing for Weak Lock Out MechanismLogin, reset and sessions
A08 Software or Data Integrity FailuresFind deserialization of untrusted data; post an unsigned webhook; check fork pull requests against deploy secretsUnsigned webhook rejected; no fork reaches secretsThe search, the handler’s verification line, workflow permissionsThe deserialization part often not, with the search as proofWSTG-BUSL-03 Test Integrity ChecksWebhook signatures and CI
A09 Security Logging and Alerting FailuresCause failed logins, a denial and an admin action, then find each in the logsEach event found with who, what, when and where; an alert reaches someoneThe log linesAlwaysWSTG-BUSL-07 Test Defenses Against Application MisuseSecurity logging
A10 Mishandling of Exceptional ConditionsSend a malformed body, a wrong type, an oversized payload and a missing field to each write endpointA client error with a safe message; no half-written recordThe requests, the responses, a read-backAlwaysWSTG-ERRH-01 Testing for Improper Error HandlingError handling and validation

The go-deeper column names one test from OWASP’s Web Security Testing Guide per row, by its id and title, for when a row needs more than one test can give it. Treat each row as a test case: these OWASP Top 10 test cases are the smallest set that still leaves evidence, and the guide holds the rest. The evidence column is the part a reviewer reads, and evidence for each OWASP category means a request, what came back, the account used and a date. Kept that way, the table doubles as an OWASP Top 10 checklist with the results filled in, and when a customer sends an application security checklist that cites OWASP, it answers them row by row.

How to run an OWASP Top 10 review, in five steps:

  1. 01 Write the edition and the review date at the top of the record.
  2. 02 List the app's surfaces: routes, server actions, storage buckets, webhooks, admin screens and any AI feature.
  3. 03 Run each category's tests against staging with two ordinary accounts and one admin account.
  4. 04 Record the request, the response and the date for every row.
  5. 05 Mark a category not applicable only with a written reason tied to this app.

A reason names something about the app: no XML parser anywhere in the dependency tree is a reason, while using a framework is not. On a multi-tenant SaaS, the OWASP security checklist gains one test in row one: change the tenant id in a write and expect a refusal. Checking the OWASP Top 10 against production is a different job with different risks, so every test here runs on staging with test accounts.

Testing OWASP Top 10 vulnerabilities manually, with a browser and those three accounts, is enough for a small app. Among OWASP Top 10 testing tools, a scanner adds coverage for misconfiguration and known-vulnerable components and proves nothing about access control, because it cannot know that user A must not read user B’s record; what a scanner does and does not cover is in a website security check. This is security testing against the OWASP Top 10 at the scale of one app and one reviewer. It is not an OWASP Top 10 pentest checklist in the attacker’s sense: every test runs against an app you own and expects a refusal.

What is OWASP Top 10 in simple terms?

The OWASP Top 10, in simple terms, is an awareness document that ranks 10 classes of web application risk from contributed data and a community survey. It is not a standard to certify against, a test plan or a certificate, so a review needs its own tests and its own evidence.

OWASP’s own words for what the OWASP Top 10 is: “a standard awareness document for developers and web application security” that represents “a broad consensus about the most critical security risks to web applications”. The 2025 edition’s introduction says eight of the ten categories come from contributed data and “the other two categories are from the Top 10 community survey”. The latest OWASP Top 10 for web application security risks is the 2025 edition, which the project page calls “the most current released version”. It ranks risks and names the weaknesses in each; it prescribes no test and grants no certificate, which is why the table above exists (my reading of both pages). Web application security best practices from OWASP live in other projects, such as its Cheat Sheet Series. The 2004 edition was published by the Open Web Application Security Project under the title “The Ten Most Critical Web Application Security Vulnerabilities”, and the organization behind the OWASP Top 10 now calls itself the Open Worldwide Application Security Project; what OWASP is covers the rest of that story.

What goes wrong without it

Picture three requests a small team gets, and what each looks like when nobody has walked the categories:

What the reviewer askedWhat the team hadWhat follows
A customer’s security questionnaire asks for a dated OWASP Top 10 reviewA scanner report that never signed in as two different usersThe access-control answer rests on a tool that never tested access control
A diligence reviewer asks for the evidence behind the access-control rowA pass with no request, no response and no dateThe reviewer has to treat the row as untested
A fix lands for one SQL injection in one handlerNo walk through the rest of the categoryThe same string-built query stays in the other handlers

Two counts from my own audits sit behind the access-control and components rows. In my June and July 2026 audits, 11 of the 21 third-party apps had unauthenticated endpoints doing privileged work. Across the 26 apps I audited in that period, 9 ran a framework version with a publicly known, reachable RCE or auth bypass, and the fix was usually a one-line version bump. Those apps are a selected set, not a random sample, so read the counts as places to look first, not as a rate for AI-built apps in general. How the same apps landed category by category is in where AI-built apps land on the OWASP Top 10.

How to prevent OWASP Top 10 vulnerabilities is the fix pages’ job, not the review’s: every category below names the page that owns its fix. The twelve checks a builder runs before launch, with their own OWASP mapping, are in the vibe coding security checklist.

How to test each category

Each of the 10 categories gets the same treatment: what it covers in one sentence, a test with an expected result, the evidence to keep, the condition under which it does not apply, and the page that owns the fix. None of the tests needs an attack tool.

Each scope sentence below is quoted from the category’s 2025 page; the tests are mine, written for an app you own and run against staging.

Broken access control

The 2025 page says access control “enforces policy such that users cannot act outside of their intended permissions.” Four tests cover it: as user A, request user B’s object by its id; as an ordinary member, call an admin action directly; with no session at all, call each API route and read each table the client bundle names; and on a multi-tenant app, change tenant_id in a write. The expected result for all four is a refusal.

A refusal has a shape, and the shape depends on the stack. A server route that checks access answers with the error status the app chose, often an unauthorized, forbidden or not-found response. On Supabase, a row-level security using clause that filters a row out “raises nothing, matches zero rows”, so a blocked read comes back empty and a blocked update or delete changes nothing, with no error; a blocked insert is a with check violation and does raise one (42501). So the evidence here is often that no data came back and nothing changed, confirmed by reading the target row back as its owner, the way Supabase’s row-level security guide pairs every denied write with a check that the row is intact. Keep the request, what came back and the two account ids. This row is never not applicable for an app with accounts.

The finding this test catches has its own name, IDOR. Insecure direct object references merged into A5:2017 Broken Access Control, and IDOR sits in A01 of the OWASP Top 10 in 2021 and in 2025, with CWE-639 on both lists.

SSRF moved: the OWASP Top 10 gave SSRF its own category, A10:2021, and the 2025 introduction says Server-Side Request Forgery “has been rolled into” Broken Access Control. To test it, give any feature that fetches a URL (an image import, a link preview, a webhook tester) an internal address you control in staging, and expect a refusal. The other server-side classes are in race conditions and the other vulnerability classes, and the fix for this row belongs to broken access control.

Security misconfiguration

The 2025 page defines it as a system, application or cloud service “set up incorrectly from a security perspective, creating vulnerabilities.” Security Misconfiguration is A02 in the 2025 OWASP Top 10, up from fifth place in 2021. Run these tests on a production build deployed to staging, because development modes are verbose on purpose: Express’s own guide notes that verbose error logging, fine while developing, “can become a security concern in a production environment.”

Request a page that does not exist and force a server error, then read both bodies for a stack trace. Read the response headers against the header list, starting with Content Security Policy without unsafe-inline. Look for default credentials, storage buckets anyone can list, a database port open to the internet, directory listing, debug mode, public source maps, and a .env or .git path that answers over HTTP. Then check the hosting platform’s own settings against what insecure defaults are. The OWASP Top 10 has no infrastructure category of its own; misconfigured servers, storage and cloud services are tested here, in my reading of the A02 scope.

In the OWASP Top 10, XXE (XML External Entities) was its own category, A4:2017, moved into misconfiguration in 2021, and CWE-611 is one of the two notable CWEs of A02:2025. The test is to find any XML parsing in the dependency tree (a SAML login, an SVG or DOCX upload, an RSS import) and confirm the parser’s options disable external entities. With no XML parser anywhere, the XXE part of this row is not applicable and says why. Evidence: the header dump, the error response and a screenshot of the platform settings.

Software supply chain and vulnerable components

The 2025 name is Software Supply Chain Failures: “breakdowns or other compromises in the process of building, distributing, or updating software.” It is the old OWASP Top 10 category for using components with known vulnerabilities, A9 in 2013 and 2017, renamed Vulnerable and Outdated Components as A06:2021 and widened in 2025 to build systems and distribution.

Audit the dependencies from the lockfile that is actually committed, and read the result for reachability, not for the count; the npm audit command covers reading the output. Check the framework’s version against its own security advisories: that single check is the finding behind the 9-of-26 count above. Confirm a lockfile is committed and that CI installs from it, and look at which packages ran install scripts, the route npm malware packages take. Keep the audit output, the framework version, the advisory you checked and the date.

Cryptographic failures: what an encryption failure looks like in a web app, and what to change

Cryptographic failures in a web app come down to 6 checks: plain HTTP or no HSTS, passwords under a fast hash, sensitive fields stored in plain text, a key in the repository, a predictable random source for tokens, and reversible encryption where a hash belongs. Each has a one-line way to see it.

A cryptographic failure, meaning in one sentence: data that cryptography should have protected was left bare, protected with a weak algorithm, or protected with a key someone else can get. The 2025 page’s own list of cryptography issues is “failures related to the lack of cryptography, insufficiently strong cryptography, leaking of cryptographic keys, and related errors.” In the OWASP Top 10, Cryptographic Failures is A04:2025, down from A02:2021; the 2017 edition covered the same ground as A3 Sensitive Data Exposure, and 2021 renamed it for the cause instead of the symptom.

What is wrongHow to see itWhat to change to
Pages or APIs served over plain HTTP, or no HSTSRequest the http:// address and see whether it redirects; read the response headers for Strict-Transport-SecurityHTTPS everywhere, plus the HSTS header, which tells browsers to use HTTPS for the host from then on
Passwords under a fast hash (MD5, SHA-1, unsalted SHA-256)Find the hashing call in the signup code and read a test user’s stored password formatA slow password hashing function: Argon2id first, then scrypt, bcrypt for legacy systems, PBKDF2 where FIPS-140 is required
Secrets or personal data stored in plain textRead a test user’s row in the database consoleField encryption, or the platform’s encryption at rest where that is the expected control
A hard-coded key or IV in the repositorySearch the code and its history for key names and literal default valuesKeys only from a secret store, with no fallback value, rotated if they were ever committed
Math.random() used for tokens or codesSearch for Math.random( near token, code or id generationcrypto.getRandomValues() in the browser, crypto.randomBytes() in Node
Reversible encryption of something that only needs comparingLook for encrypt and decrypt calls on passwords or API keysA hash, and for passwords a password hashing function

The last column answers the best way to prevent a cryptographic failure: each fix is a setting or a library call, not new cryptography. For passwords, the OWASP Password Storage Cheat Sheet gives the order above and the reason: “Fast hashing algorithms such as SHA‑256 are not suitable for password storage because they allow attackers to perform large numbers of guesses quickly.” Password length and composition rules are a separate question: NIST minimum password length. For stored fields, the choice between field encryption and at-rest encryption is in database encryption.

The key row needs the code and the deployed settings read together. In my June and July 2026 audits, a medical app’s login-token signing key had two known values in the repository: the code fell back to a literal default when the variable was unset, and the production stack set the variable to the file path of a container secret, which the backend never read, so the operative key was the path string itself. The report records one caveat: a strong key set outside the repository would bypass both. The lesson I take from it is that neither the code nor the settings screen alone shows which key is live, so the evidence for this row is both, side by side.

The random-source row earns its place from the 2025 page’s own account of cryptographic vulnerabilities: three of the most common CWEs in this category “involved the use of a weak pseudo-random number generator”. CWE-328 is mapped to the Cryptographic Failures category of the OWASP Top 10: it is on the A04:2025 list, under its older name Reversible One-Way Hash, and on the A02:2021 list. MITRE’s CWE-328 entry now calls it Use of Weak Hash: a digest weak enough that someone can find the input, a second input with the same hash, or two inputs that collide. Cryptography vulnerabilities inside a library itself reach you through the components row, as advisories. An encryption failed message on a phone or in an email client is a different topic, a device or mail setting, not this web app category.

MD5 vs SHA-1, and whether either is secure

MD5 and SHA-1 are both broken for collision resistance, so neither is secure for new security work, and comparing the two is the wrong question. Use SHA-256 or stronger for integrity, and a password hashing function for passwords, where even SHA-256 is wrong because it is fast. MD5 still detects accidental corruption.

MD5 was broken in stages that RFC 6151 dates: pseudo-collisions for its compression function in 1993, a collision pair for that function in 1996, the first paper showing two collision pairs for MD5 itself in 2004, and later attacks that “can find MD5 collision in about one minute on a standard notebook PC”. That is why MD5 is insecure: anyone can produce two inputs with the same MD5 hash, and the RFC calls it “no longer acceptable where collision resistance is required such as digital signatures.” The 2025 OWASP page lists MD5 and SHA1 as “deprecated hash functions”.

SHA-1 is no more secure for new work. NIST’s retirement of SHA-1 says collision attacks “have been used to undermine SHA-1 in recent years” and that SHA-1 “should be phased out by Dec. 31, 2030”; NIST’s hash functions page adds that it deprecated SHA-1 in 2011 and disallowed it for digital signatures at the end of 2013. Between MD5, SHA-1 and SHA-256, pick SHA-256 for integrity; NIST’s advice to anyone relying on SHA-1 is to “migrate to SHA-2 or SHA-3 as soon as possible.”

Speed is no reason to pick either. For passwords, speed is the defect: the password cheat sheet says slow hashes are the point, “unlike algorithms such as MD5 and SHA-1, which were designed to be fast”. MD5 keeps one honest use: RFC 6151 says that where an MD5 checksum is used inline with a protocol “solely to protect against errors, an MD5 checksum is still an acceptable use.” Label it in the code as a corruption check, never as a security control.

SHA-256 in JavaScript, checksums and SRI hashes

In JS, SHA-256 needs no library and no checksum generator site. The browser has crypto.subtle.digest(), available only in secure contexts per SubtleCrypto.digest on MDN, and Node has createHash('sha256') in Node’s crypto module. A file checksum is sha256sum (GNU coreutils) or shasum -a 256, where plain shasum defaults to SHA-1.

// Browser (secure contexts only)
await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text))
// Node.js: import { createHash } from 'node:crypto'
createHash('sha256').update(text).digest('hex')
# Shell: a file checksum, then an SRI value for a script
sha256sum app.js
cat app.js | openssl dgst -sha384 -binary | openssl base64 -A

No SHA integrity generator site is needed either. A Subresource Integrity value is the algorithm name, a dash and the base64 digest; MDN’s Subresource Integrity guide allows sha256, sha384 and sha512 and gives the OpenSSL command above. SHA-256 itself is not retired: NIST’s hash functions page lists it among the approved SHA-2 algorithms of FIPS 180-4, with 128 bits of collision resistance against under 80 for SHA-1. Pasting a secret into an online hash generator is the failure this category is about, since the value has left your control.

Injection, including SQL injection and XSS

SQL injection is classified under Injection, A03 in the 2021 edition, and cross-site scripting joined the same category that year. Both are tested without an attack tool: look for string-built queries and unescaped rendering, then confirm a single quote causes no database error and a tag shows as plain text.

In the OWASP Top 10, injection is A05:2025, down from third place in 2021, and the 2025 page defines it as “an application flaw that allows untrusted user input to be sent to an interpreter (e.g. a browser, database, the command line) and causes the interpreter to execute parts of that input as commands.” The 2021 OWASP Top 10 classification name for SQL injection is A03:2021 Injection; in 2017 it was A1:2017 Injection, and XSS had its own OWASP Top 10 entry, A7:2017, until 2021 folded it into Injection. Cross-site scripting stays in the OWASP Top 10 under Injection in 2025, which the page describes as “high frequency/low impact” next to SQL injection’s “low frequency/high impact”.

The tests stay defensive. Search the code for string concatenation or template literals inside query calls, and for raw-query helpers such as DB::raw, RawSQL or a Supabase .or() or .filter() built from user input. Send a single quote through each search and filter field: the expected answer is a normal response, results or a validation message, never a database error. For XSS, save <b>test</b> in every user-controlled field that is shown back later and confirm it displays as the literal text, then search for dangerouslySetInnerHTML, v-html and innerHTML. Keep the search results and the responses. The fixes are SQL injection prevention and how to mitigate cross-site scripting.

Insecure design

Insecure design is a missing control, not a bug in one. The 2025 page puts it plainly: “An insecure design cannot be fixed by a perfect implementation as needed security controls were never created to defend against specific attacks.” In the OWASP Top 10, insecure design is A06:2025; it first appeared as A04:2021. Business logic flaws belong to this OWASP Top 10 row, since the page says the category “includes flaws in the business logic of an application”.

The tests are questions with a yes or no and a request as proof. Can a price, a quantity or a plan be set from the client? Will a coupon, a trial or a referral work twice? Can a multi-step flow be entered at step three? Is there any limit on the most expensive action (rate limiting in API endpoints)? The evidence for this row is a one-page threat modeling note with each answer and its proof, and no app gets to mark this row not applicable.

Authentication failures

The 2025 page: “When an attacker is able to trick a system into recognizing an invalid or incorrect user as legitimate, this vulnerability is present.” Broken authentication in the OWASP Top 10 was A2:2017 Broken Authentication, became A07:2021 Identification and Authentication Failures, and is A07:2025 Authentication Failures.

Try a known and an unknown email on login and on password reset and compare the answers; the page asks for “the same messages for all outcomes”. Send repeated wrong passwords and expect a throttle or a lockout. Use a reset link twice, and once after a long wait. Change the password and replay the old session, remembering that a stateless access token stays valid until it expires, so wait out its lifetime before calling that a failure; that difference is part of JWT security. Check that admin accounts need a second factor. Keep the responses side by side. The fixes live in authentication best practices and the JWT page. When a managed provider runs every flow, the row records the provider’s settings instead of a pass.

Software or data integrity failures

The 2025 scope: integrity failures “relate to code and infrastructure that does not protect against invalid or untrusted code or data being treated as trusted and valid.” In the OWASP Top 10 2021, the category that includes insecure deserialization is A08:2021 Software and Data Integrity Failures, which absorbed A8:2017 Insecure Deserialization; 2025 renamed it Software or Data Integrity Failures.

Find any place the app turns untrusted data into objects (pickle.loads, Java deserialization, yaml.load, eval on JSON); a TypeScript app often has none, and the row says so with the search as proof. Post an unsigned request to each webhook endpoint and expect a rejection. Check that third-party scripts on pages that take payments carry an integrity attribute. Check whether a pull request from a fork can reach deploy secrets, which is covered in CI CD security best practices, and whether any auto-update channel checks a signature. Evidence: the search, the webhook handler’s verification line and the workflow permissions.

Logging and alerting failures

The 2025 page: “Without logging and monitoring, attacks and breaches cannot be detected, and without alerting it is very difficult to respond quickly and effectively during a security incident.” Cause five failed logins, one access-control denial and one admin action, then search the logs for each straight away, looking for who, what, when and from where. Straight away matters: Vercel keeps runtime logs for 1 hour on Hobby and 1 day on Pro, so a search made the next day can come back empty even when logging works. Confirm no password, token or card number appears in those lines, and that an alert reaches a person. The log lines are the evidence, and how to prevent insufficient logging and monitoring owns the fix.

Codes without a year mislead most in this part of the list. OWASP Top 10 A5 was Broken Access Control in 2017 and Security Misconfiguration in 2021; OWASP Top 10 A6 was Security Misconfiguration in 2017 and Vulnerable and Outdated Components in 2021; in 2025 they are Injection and Insecure Design. The crosswalk below settles any code.

Mishandling of exceptional conditions

The 2025 page: it “happens when programs fail to prevent, detect, and respond to unusual and unpredictable situations, which leads to crashes, unexpected behavior, and sometimes vulnerabilities.” Send a malformed body, a wrong type, an oversized payload and a missing required field to each write endpoint. Expect a client-error status with a safe message, never a 500 error with a stack trace and never a half-written record; the two fixes come from API error handling best practices and input validation in a web app.

In the OWASP Top 10, input validation had its own entry in the 2004 list, A1 Unvalidated Input, and has none in the 2013, 2017, 2021 or 2025 lists. Validating data input is now the control behind this OWASP Top 10 category and behind injection: CWE-20 Improper Input Validation is mapped to A05:2025, and the A10 page says exceptional conditions “can be caused by missing, poor, or incomplete input validation”. Denial of service was A9 in the 2004 OWASP Top 10 and is not a current category; the 2025 introduction treats it as a symptom, so resource exhaustion is tested under insecure design and rate limits. Buffer overflow was A5 in the 2004 OWASP Top 10, a memory-safety flaw that application code in JavaScript, Python or C# rarely meets in my reading (the 2004 list itself called Java environments “immune to these attacks (except for overflows in the JVM itself)”), and it still matters in native dependencies, which the components row covers.

Which OWASP Top 10 category a finding falls under

A finding’s OWASP category depends on the edition, so a code without its year is ambiguous: the same code has meant different things in different editions. The crosswalk maps 20 common findings to their 2017, 2021 and current codes, and names the ones that were never on the list.

A report line that cites A3 alone could mean Sensitive Data Exposure (2017), Injection (2021) or Software Supply Chain Failures (2025). The 2021 codes come from the 2021 edition and its category lists, and the 2017 codes from the 2017 category pages and release notes.

Finding201720212025Where to test it
SQL injectionA1 InjectionA03 InjectionA05 InjectionInjection
Cross-site scripting (XSS)A7 XSSA03 InjectionA05 InjectionInjection
Cross-site request forgery (CSRF)none (A8 in 2013, dropped)A01 Broken Access ControlA01 Broken Access ControlBroken access control
XML external entities (XXE)A4 XXEA05 Security MisconfigurationA02 Security MisconfigurationSecurity misconfiguration
Server-side request forgery (SSRF)noneA10 SSRFA01 Broken Access ControlBroken access control
Insecure direct object reference (IDOR)A5 Broken Access ControlA01 Broken Access ControlA01 Broken Access ControlBroken access control
Open redirectnone (A10 in 2013, dropped)A01 Broken Access ControlA01 Broken Access ControlBroken access control
Path traversalA5 Broken Access ControlA01 Broken Access ControlA01 Broken Access ControlBroken access control
Insecure deserializationA8 Insecure DeserializationA08 Software and Data Integrity FailuresA08 Software or Data Integrity FailuresSoftware or data integrity failures
Weak hash (CWE-328)A3 Sensitive Data ExposureA02 Cryptographic FailuresA04 Cryptographic FailuresCryptographic failures
Sensitive data exposure (the 2017 name)A3 Sensitive Data ExposureA02 Cryptographic FailuresA04 Cryptographic FailuresCryptographic failures
User enumerationA2 Broken Authentication (my mapping)A07 Identification and Authentication FailuresA07 Authentication FailuresAuthentication failures
No limit on login attemptsA2 Broken AuthenticationA07 (CWE-307)A07 (CWE-307)Authentication failures
Information disclosure in error messagesA6 Security MisconfigurationA04 Insecure Design (CWE-209)A10 Mishandling of Exceptional Conditions (CWE-209)Mishandling of exceptional conditions
Default credentialsA6 Security MisconfigurationA05 Security MisconfigurationA07 Authentication Failures (CWE-1392)Security misconfiguration (run the test there; file the finding under A07 in a 2025 record)
Outdated framework with a known flawA9 Using Components with Known VulnerabilitiesA06 Vulnerable and Outdated ComponentsA03 Software Supply Chain FailuresSoftware supply chain and vulnerable components
Unsigned webhook acceptednoneA08 (CWE-345)A08 (CWE-345)Software or data integrity failures
Security events not loggedA10 Insufficient Logging & MonitoringA09 Security Logging and Monitoring FailuresA09 Security Logging and Alerting FailuresLogging and alerting failures
Business logic abusenoneA04 Insecure Design (CWE-840)A06 Insecure DesignInsecure design
Prompt injectionnot on the web listnot on the web listnot on the web list; LLM01:2025 in the LLM listSee the LLM links below

Where the 2017 column says none, no 2017 category covers the finding, in my reading of that edition’s ten; the 2021 and 2025 codes follow each category’s own CWE list or text. CSRF left the OWASP Top 10 in 2017: it was A8 in 2013, the 2017 release notes dropped it because “many frameworks include CSRF defenses, it was found in only 5% of applications”, and since 2021 its CWE-352 sits under A01. The test and the fix are both a matter of CSRF mitigation. Open redirect took a similar road in the OWASP Top 10 2021: A10 in 2013 as Unvalidated Redirects and Forwards, dropped in 2017, then mapped to A01 through CWE-601. Information disclosure in the OWASP Top 10 crosses three categories: an error message that leaks internals was a misconfiguration in 2017, an insecure-design CWE in 2021 and an exceptional-conditions CWE in 2025.

The OWASP Top 10 2025 vs 2021, in three lines from the edition’s introduction, which counts “two new categories and one consolidation”:

  • Server-Side Request Forgery, A10:2021, was rolled into A01 Broken Access Control.
  • Software Supply Chain Failures (A03:2025) expands A06:2021 to the whole chain of dependencies, build systems and distribution, and Mishandling of Exceptional Conditions (A10:2025) is new.
  • Security Misconfiguration moved from fifth to second, Cryptographic Failures fell from second to fourth, and Authentication Failures and Security Logging and Alerting Failures took new names.

Between the OWASP Top 10 2021 and 2017, the moves were merges and renames: Sensitive Data Exposure became Cryptographic Failures, XSS joined Injection, XXE joined Security Misconfiguration, Insecure Deserialization joined the new Software and Data Integrity Failures category, and Insecure Design and SSRF arrived as the other two new categories.

The OWASP Top 10 vs the SANS Top 25 is a comparison of different units. The OWASP Top 10 ranks ten risk categories for web applications, while the CWE Top 25, run by MITRE’s CWE program and published as the CWE/SANS Top 25 in its 2009 to 2011 editions, ranks specific weaknesses across all software from CVE Records, 39,080 of them in its 2025 dataset. The bridge is the CWE id: each Top 10 category lists the CWEs it contains, 248 of them across the 2025 edition, so a CWE is the precise name and the category is its group.

The Top 10 is the web list. The API list is a separate document, mapped in the API security checklist for AI-built apps, and so is mobile, in mobile app security best practices. Prompt injection is on neither: the 2025 Injection page sends it to the LLM list as LLM01:2025, which the OWASP LLM Top 10 and what is prompt injection cover.

The same review on Django, Laravel, Node.js, ASP.NET Core and Java

A framework closes some rows by default and none of them all. The table uses each framework’s own security documentation; the Next.js with Supabase row is there because it is a common stack for apps made with AI builders (my reading).

FrameworkOn by default, in its own docsStill needs the test
DjangoTemplate auto-escaping against most XSS; protection against most CSRF attacks when enabled and used where appropriate; querysets built with query parameterization; X-Frame-Options middlewareRaw SQL, extra() and RawSQL; login throttling, which Django does not do; access control, design, logging, dependencies
LaravelThe request forgery middleware in the web middleware group; PDO parameter binding in the query builderDB::raw and other raw expressions; routes outside the web group; access control, design, logging, dependencies
Express on Node.jsLittle: it sends an X-Powered-By header by default, and Helmet sets security headers once you add itInput validation, headers, CSRF, access control, design, logging, dependencies
ASP.NET CoreRazor encodes output from variables; CSRF middleware on by default in apps built with WebApplication.CreateBuilderJSON endpoints, which that middleware does not reject cross-origin; Html.Raw; access control, design, logging, dependencies
JavaDepends on the framework; not stated in the cheat sheet indexThe Java Security, Injection Prevention in Java and Deserialization cheat sheets as the test list
Next.js with SupabaseReact DOM escapes values embedded in JSX; most Supabase filter methods take values rather than raw syntaxdangerouslySetInnerHTML; .filter(), .not() and .or() values, which Supabase says must be sanitized; row-level security on every table

Django’s security documentation points readers to the OWASP Top 10 itself and says that while Django has tools for some of the issues, “other issues must be accounted for in the design of your project.” For Laravel, the OWASP Top 10 rows the docs close are CSRF, through the middleware described in Laravel’s CSRF protection, and SQL injection through query binding. On Node.js with Express, the OWASP Top 10 review starts from almost nothing on by default; Express’s security best practices say the responsibility for handling user input “is yours”. ASP.NET Core security names features for four OWASP Top 10 problems: XSS, SQL injection, CSRF and open redirects. For Java, OWASP’s cheat sheets are the nearest thing to a framework page: the OWASP Cheat Sheet Series has Java Security and Injection Prevention in Java as sheets of their own.

The rows no framework closes are access control, insecure design, logging and the supply chain, in my reading of the documents above. The tests do not change with the stack; only the search patterns and the shape of a refusal do.

How to verify it

An OWASP review is verified by 5 checks on the record itself: every row has a result or a justified not-applicable, every pass has evidence someone can re-run, every fail has a retest, the edition and date are stated, and a second person reproduces three rows.

  1. 01 Every one of the ten rows has a result: pass, fail with a finding id, or not applicable with a reason a stranger would accept.
  2. 02 Every pass has evidence someone else can re-run: the request, what came back, the date and the account used.
  3. 03 Every fail has a fix, a retest and the retest's evidence.
  4. 04 The edition and the review date are on page one, and every finding carries its code with the year.
  5. 05 A second person re-runs three rows picked at random and gets the same results.

A review with ten passes and no evidence fails this section. The record is also not an OWASP Top 10 penetration test: a review records a test per category, while a penetration test probes chosen surfaces the way an attacker would, which web application penetration testing covers, and a pentest scoped to the OWASP Top 10 is still that other job. Neither one is a certificate. The reviewer’s view of the code itself is a separate job: the secure code review checklist.

In the Production Hardening Sprint, deliverable 3.7 is verified this way: deliver category-level results and supporting test evidence, with justified non-applicable cases identified.

Where the sprint does this

Deliverable 3.7 of the Production Hardening Sprint reviews the application against the OWASP Top 10 and records findings, fixes and evidence by category. The targeted security tests cover the five priority attack surfaces documented in the report, and the package also includes an OWASP review and a controls checklist with evidence. The production readiness report, deliverable 13.1, accounts for all 123 IDs, keeps failures visible until resolved and explains genuine non-applicable items. Formal third-party certifications and independent audit opinions are separate from the sprint deliverables. The full list of deliverables is in the published scope.

Common questions about an OWASP review

What is the OWASP Top 10 used for?

The OWASP Top 10 is used as what OWASP calls it, an awareness document, and in practice as a shared vocabulary for findings and a baseline that customers and reviewers ask about. It tells a team which classes of web risk to look at first; it does not say how to test them, which is why a review adds its own tests and evidence.

What are the latest vulnerabilities?

The Top 10 ranks classes of weakness, not individual flaws, so it does not track this week’s vulnerabilities. The recent ones that touch your app come from your dependency audit and your framework’s security advisories, which is the supply chain row of the review.

What are the top 10 principles of OWASP?

The OWASP list of things to build in, rather than risks to avoid, is the OWASP Top 10 Proactive Controls, written for developers first, with 2024 as its latest numbered edition. Its stated aim is “to raise awareness about application security by describing the most important areas of concern that software developers must be aware of.”

The list itself is at the OWASP Top 10 Proactive Controls.

What is an OWASP vulnerability?

An OWASP vulnerability is not a formal type: it means a weakness that falls under one of the Top 10 categories. The precise name is its CWE id, which each category page lists, such as CWE-89 for SQL injection under A05:2025.

Not in itself: OWASP describes the Top 10 as an awareness document for developers, not as a law or a certification. Whether a contract, a customer questionnaire or another standard you follow requires it depends on that document, and this is general information, not legal advice.