Web and API security
SQL Injection Explained with OWASP Juice Shop
How SQL injection changes a query's meaning, why parameterized queries fix it, and a Juice Shop login lab with a Python sqlite3 demo.
What the OWASP Top 10 is, what each 2025 category means, how to defend it, and how to map Juice Shop challenges to it.
The OWASP Top 10 is a short list of the ten risk categories that matter most for web applications. OWASP, the Open Worldwide Application Security Project, is a nonprofit that publishes free security guidance. The current edition is 2025, the eighth in the series.
The Top 10 is an awareness document. It names the failures that keep showing up in real applications, so developers, testers and managers can talk about them with the same words. It is not a test, a certification or a finished checklist.
The 2025 edition combines two kinds of evidence. The first is testing data: thirteen named organisations and several anonymous donors reported results covering more than 2.8 million applications, counting how many had at least one instance of each weakness. The second is vulnerability data: about 220,000 CVE records from the US National Vulnerability Database, mapped to 643 CWEs. Automated tests cannot see everything, so two of the ten categories came from a community survey.
Each category groups related CWEs, the Common Weakness Enumeration maintained by MITRE. OWASP says the 2025 list covers 248 CWEs.
Most web security failures come from a few repeated decisions. An app trusts a value the browser sent. A route checks that a user is logged in but never checks that they own the record. A password is stored in a way that falls apart when the database leaks. The Top 10 gives those decisions names.
Names help in practice. In a design review you can ask where access control is decided. In a code review you can flag a missing ownership check and cite A01. In an incident report you can describe the root cause instead of the symptom.
The order follows the 2025 edition. It is a reading order, not a ranking of what to fix first in your app. Each section gives a plain example, the main defence, the CWEs OWASP maps to the category and a cheat sheet.
Access control decides what an authenticated user may do. This category covers decisions that are missing, wrong, or enforced only in the browser. OWASP reports that every tested application had some form of this flaw.
Example: an order page loads at /orders/1041. Changing the number to /orders/1042 shows another customer's order, because the server never checks who owns it.
Main defence: deny by default, and check ownership and permissions on the server for every request, in shared code rather than in each handler.
CWEs: CWE-284 Improper Access Control, CWE-639 Authorization Bypass Through User-Controlled Key, CWE-862 Missing Authorization, CWE-918 Server-Side Request Forgery (SSRF), among 40 mapped entries.
Cheat sheet: Authorization Cheat Sheet.
A system is only as secure as its configuration. This category covers default accounts left in place, debug features switched on, verbose errors, missing security headers and cloud storage with the wrong permissions.
Example: a staging server runs with the default admin password from the install guide and shows full stack traces to any visitor.
Main defence: use a repeatable hardening process. Configure development, QA and production the same way, with different credentials in each, and remove the features and samples you do not use.
CWEs: CWE-16 Configuration, CWE-260 Password in Configuration File, CWE-15 External Control of System or Configuration Setting, among 16 mapped entries.
Reference: ASVS chapter V13 Configuration. OWASP lists no cheat sheet for this category.
Your application runs code you did not write. This category covers the path software takes from source to production: dependencies, build tools, registries and update channels. OWASP notes that the category has grown beyond known-vulnerable components, and that it ranked first in the community survey.
Example: a small utility package in your dependency tree is replaced by a version containing malicious code, and your next build installs it.
Main defence: know what you ship. Generate a software bill of materials (SBOM), track transitive dependencies, remove unused packages and keep the component inventory current.
CWEs: CWE-1104 Use of Unmaintained Third Party Components, CWE-1395 Dependency on Vulnerable Third-Party Component, and four other mapped entries.
Cheat sheets: Vulnerable Dependency Management Cheat Sheet and Dependency Graph SBOM Cheat Sheet.
This category covers missing cryptography, weak algorithms, poor key handling and skipped certificate checks. The common mistake is often a missing decision rather than a broken algorithm: data travels over plain HTTP, or sits in storage nobody reviewed.
Example: a login form sends passwords over plain HTTP, or stores them with a fast hash and no salt.
Main defence: classify your data first, then decide what needs encryption in transit and at rest. Use trusted implementations of standard algorithms, and do not keep sensitive data you do not need.
CWEs: CWE-261 Weak Encoding for Password, CWE-319 Cleartext Transmission of Sensitive Information, CWE-321 Use of Hard-coded Cryptographic Key, among 32 mapped entries.
Cheat sheets: Transport Layer Protection Cheat Sheet and Password Storage Cheat Sheet.
Injection happens when untrusted input reaches an interpreter, such as a SQL engine, an operating system shell or a browser, and the interpreter runs part of that input as instructions. OWASP lists SQL, NoSQL, OS command, ORM, LDAP and expression language injection as common forms. In the 2025 edition, cross-site scripting (XSS) sits in this category too.
Example: a search handler joins the user's text into an SQL string. A quote character in that text changes the meaning of the query.
Main defence: use a safe API that keeps data separate from commands, such as parameterised queries or an ORM. Validate input on the server with allow lists. Where dynamic output is unavoidable, use the escaping rules of the target interpreter. Table and column names cannot be escaped that way, so keep them out of user input altogether.
CWEs: CWE-20 Improper Input Validation, CWE-74 Injection, CWE-78 OS Command Injection, CWE-79 Cross-site Scripting, among 37 mapped entries.
Cheat sheets: Injection Prevention Cheat Sheet and SQL Injection Prevention Cheat Sheet.
No implementation can fix a design that never included a defence. This category covers controls that were never planned: business logic that can be abused, recovery flows that rely on guessable answers, or privileges granted by default.
Example: a discount endpoint accepts the same coupon again and again, because nobody modelled reuse as a threat.
Main defence: threat model critical flows such as authentication, access control and payments before you build them. The threat modelling article shows one way to ask those questions. Reuse vetted secure design patterns instead of inventing a new one for each feature.
CWEs: CWE-269 Improper Privilege Management, CWE-256 Unprotected Storage of Credentials, CWE-73 External Control of File Name or Path, among 39 mapped entries.
Cheat sheet: Secure Product Design Cheat Sheet.
These failures let the wrong person in, or let an attacker keep trying until one attempt works. They include credential stuffing, password spraying, weak account recovery, missing multi-factor authentication (MFA) and sessions that stay valid after logout.
Example: an admin login has no rate limit and no MFA. An attacker tries username and password pairs from earlier breaches until one works.
Main defence: enforce MFA where you can, block automated attempts, remove default accounts and check new passwords against a list of common ones. OWASP suggests the 10,000 worst passwords.
CWEs: CWE-287 Improper Authentication, CWE-259 Use of Hard-coded Password, CWE-290 Authentication Bypass by Spoofing, among 36 mapped entries.
Cheat sheet: Authentication Cheat Sheet.
Integrity means the code or data is what you expect and was not changed on the way. This category covers auto-updates without signature checks, scripts loaded from a CDN with no integrity check, CI/CD pipelines that pull artifacts from unverified places, and deserialisation of untrusted objects.
Example: a page loads a JavaScript file from a third-party CDN with no integrity attribute. If that file is modified, every visitor runs the modified code.
Main defence: sign what you ship and verify the signature before use. Limit package managers to trusted repositories, and require review for pipeline and configuration changes.
CWEs: CWE-345 Insufficient Verification of Data Authenticity, CWE-494 Download of Code Without Integrity Check, CWE-502 Deserialization of Untrusted Data, among 14 mapped entries.
Cheat sheet: Software Supply Chain Security Cheat Sheet.
Without logs and alerts, a breach can run for months unseen. This category covers missing records of logins and access control failures, logs kept only on a machine that could be compromised, alerts nobody reads, and logs that leak secrets.
Example: failed logins for an admin account are never recorded, and the log line for a password reset contains the new password.
Main defence: log authentication and access control failures with enough context to investigate, encode log data before writing it, keep secrets out of logs, and send logs somewhere the application host cannot rewrite.
CWEs: CWE-778 Insufficient Logging, CWE-532 Insertion of Sensitive Information into Log File, CWE-117 Improper Output Neutralization for Logs, among 5 mapped entries.
Cheat sheets: Logging Cheat Sheet and Application Logging Vocabulary Cheat Sheet.
Software fails. This category is about how it fails: a crash that leaks data, a check skipped because a call returned an error, or a multi-step operation that carries on after one step failed.
Example: a payment call times out, the code treats the timeout as success, and the order ships unpaid.
Main defence: catch errors where they happen and handle them on purpose. Add a global exception handler as a safety net. When a multi-step operation fails part way, roll it back and fail closed.
CWEs: CWE-209 Generation of Error Message Containing Sensitive Information, CWE-252 Unchecked Return Value, CWE-248 Uncaught Exception, among 24 mapped entries.
Cheat sheet: Error Handling Cheat Sheet.
It is not a complete standard. Ten categories cannot describe every requirement of a secure application, and many risks sit outside the list. Passing a review against the Top 10 does not make an application secure.
It is not a checklist you can finish. Categories describe causes, so one feature can touch several of them, and one category covers many different bugs. Teams that treat it as a checkbox often fix the examples and keep the pattern that produced them.
It is not where requirements live. For that, OWASP publishes the Application Security Verification Standard (ASVS), a set of security requirements for designing, building and testing web applications and services. The current version is 5.0.0, published on 30 May 2025. Use the Top 10 to explain risk and decide where to look first. Use ASVS when you need requirements to build against and verify.
You will run OWASP Juice Shop, a deliberately vulnerable web application, on your own machine. You will read its scoreboard and map three challenge categories to Top 10 entries. You do not exploit anything. Read the challenge descriptions, not solutions, and keep the app bound to localhost.
You need Docker. The output below comes from Docker 29.8.2 on Windows 11 with Git Bash. The commands work in any POSIX shell.
docker --version
docker info --format '{{.ServerVersion}}'Observed output:
Docker version 29.8.2, build 7fc2dff
29.8.2docker run -d -p 127.0.0.1:3000:3000 bkimminich/juice-shopThe 127.0.0.1: prefix publishes the port on the loopback interface only, so other machines cannot reach it. On the machine where I ran these steps, a container from the same image was already running as juice-local, so I did not start a second one. Check what is running:
docker ps --format '{{.Names}} {{.Image}} {{.Ports}}'The Juice Shop line of the observed output:
juice-local bkimminich/juice-shop 127.0.0.1:3000->3000/tcpcurl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/
curl -s http://127.0.0.1:3000/rest/admin/application-versionObserved output:
200
{"version":"20.3.0"}Your version may differ. Write it down, because challenge names and categories change between releases.
curl -s http://127.0.0.1:3000/api/Challenges/ -o challenges.json
python -c "import json,collections; d=json.load(open('challenges.json'))['data']; print(len(d)); [print(v,k) for k,v in sorted(collections.Counter(x['category'] for x in d).items())]"Observed output:
116
12 Broken Access Control
4 Broken Anti Automation
9 Broken Authentication
5 Cryptographic Issues
12 Improper Input Validation
14 Injection
3 Insecure Deserialization
6 Miscellaneous
4 Observability Failures
5 Security Misconfiguration
3 Security through Obscurity
17 Sensitive Data Exposure
2 Unvalidated Redirects
9 Vulnerable Components
9 XSS
2 XXEOpen http://127.0.0.1:3000/#/score-board in your browser and compare its categories with the counts above. If the numbers differ, note your Juice Shop version.
This is one reasonable mapping. Yours can differ if you can justify it in a sentence.
| Juice Shop category | Challenges in category | Example challenge (difficulty 1 to 6) | Scoreboard description | Top 10:2025 entry |
|---|---|---|---|---|
| Broken Access Control | 12 | Admin Section (2) | Access the administration section of the store. | A01 Broken Access Control |
| Injection | 14 | Login Admin (2) | Log in with the administrator's user account. | A05 Injection |
| Security Misconfiguration | 5 | Error Handling (1) | Provoke an error that is neither very gracefully nor consistently handled. | A02 Security Misconfiguration |
Why each row fits:
Juice Shop's category names are its own labels. Its XSS category, for example, maps to A05 in the 2025 list. Map by root cause and cite the CWE.
docker ps --format '{{.Names}} {{.Image}}'
docker stop <container-name>
docker rm <container-name>Replace <container-name> with the name from the first command. The container was started with -d and without --rm, so it stays on disk after it stops until you remove it.
0.0.0.0 or a cloud host puts an intentionally vulnerable application on the internet.Web and API security
How SQL injection changes a query's meaning, why parameterized queries fix it, and a Juice Shop login lab with a Python sqlite3 demo.
Web and API security
Learn reflected, stored and DOM-based XSS, why output encoding depends on context, and how CSP adds defence in depth, in a local lab.
Web and API security
Cross-site request forgery uses your browser's cookies against you. Learn the defences in order of strength and test SameSite with a Flask lab.