OWASP Top 10 Testing Guide: How to Test for the Most Critical Web Vulnerabilities
Security testing is not optional. The OWASP Top 10 is the industry-standard reference for the most critical web application security risks, updated regularly based on real-world breach data. If your application has not been tested against every category in this list, it has not been security tested. This guide walks you through each category with specific test cases, tools, and HTTP-level examples you can use today.
What Is the OWASP Top 10?
The Open Web Application Security Project (OWASP) is a nonprofit that publishes freely available security guidance. Their Top 10 list, last updated in 2021, represents a broad consensus about the most impactful vulnerabilities affecting web applications. The list is not exhaustive — it is a starting point. Every application needs to be tested against all 10 categories, plus any domain-specific risks unique to its architecture.
The current 2021 list is:
- Broken Access Control
- Cryptographic Failures
- Injection
- Insecure Design
- Security Misconfiguration
- Vulnerable and Outdated Components
- Identification and Authentication Failures
- Software and Data Integrity Failures
- Security Logging and Monitoring Failures
- Server-Side Request Forgery (SSRF)
Let's test each one.
A01: Broken Access Control
Broken access control is the most common critical vulnerability today. It happens when users can act outside their intended permissions — accessing other users' data, performing admin functions, or bypassing authorization entirely.
Test Cases
Horizontal privilege escalation — Can user A access user B's resources?
GET /api/users/12345/profile HTTP/1.1
Host: app.example.com
Authorization: Bearer <user_A_token>Change 12345 to another user's ID. If you get back user B's data, the application has broken access control.
Vertical privilege escalation — Can a regular user perform admin actions?
POST /api/admin/users/delete HTTP/1.1
Host: app.example.com
Authorization: Bearer <regular_user_token>
Content-Type: application/json
{"userId": "99"}If this succeeds, authorization is not being checked on the server side.
Force browsing — Can unauthenticated users access protected pages?
GET /admin/dashboard HTTP/1.1
Host: app.example.com
(no Authorization header)Tools
- Burp Suite: Use the Repeater to replay requests with different tokens or no token
- OWASP ZAP: Active scanner checks for access control issues automatically
- Custom scripts: Automate IDOR testing across all resource IDs
A02: Cryptographic Failures
Previously called "Sensitive Data Exposure," this category covers failures in how applications protect data in transit and at rest. Common issues include weak cipher suites, unencrypted sensitive data, and broken TLS configurations.
Test Cases
TLS configuration testing with testssl.sh:
testssl.sh --severity HIGH https://app.example.comLook for: SSLv3, TLS 1.0, RC4 ciphers, NULL ciphers, and expired certificates.
Mixed content — Does the page load HTTP resources over HTTPS?
Open browser DevTools → Console. Look for "Mixed Content" warnings.
Sensitive data in URLs — Tokens, passwords, or PII should never appear in query strings:
GET /reset?token=abc123&email=user@example.com HTTP/1.1This exposes the token in server logs, browser history, and Referer headers.
Weak password hashing — If you have database access during a pentest, check that passwords are hashed with bcrypt, Argon2, or scrypt — not MD5 or SHA1.
Tools
- testssl.sh: Comprehensive TLS scanner
- SSL Labs: Online TLS grader at ssllabs.com/ssltest
- OWASP ZAP: Flags insecure cookies and missing security headers
A03: Injection
Injection covers SQL injection, NoSQL injection, command injection, LDAP injection, and more. Any interpreter that receives untrusted data is a potential injection target.
Test Cases
SQL Injection — Try a simple payload in any input:
' OR '1'='1Command Injection — Test file upload filenames, ping utilities, or any field passed to system commands:
; ls -la
| cat /etc/passwd
`whoami`LDAP Injection — Test login forms against LDAP backends:
*)(|(password=*)For full SQL injection testing detail, see our dedicated SQL injection testing guide.
Tools
- sqlmap: Automated SQL injection detection and exploitation
- Burp Suite: Manual injection testing with Intruder for fuzzing
- OWASP ZAP: Active scanner with injection rules
A04: Insecure Design
Insecure design is about missing or inadequate security controls at the architecture level. Unlike the other categories, this is not a coding bug — it is a design flaw. Examples include missing rate limiting, no account lockout policy, or a password reset flow that can be manipulated.
Test Cases
Missing rate limiting on sensitive endpoints:
for i <span class="hljs-keyword">in $(<span class="hljs-built_in">seq 1 100); <span class="hljs-keyword">do
curl -s -o /dev/null -w <span class="hljs-string">"%{http_code}\n" \
-X POST https://app.example.com/api/login \
-H <span class="hljs-string">"Content-Type: application/json" \
-d <span class="hljs-string">'{"email":"user@test.com","password":"wrong"}'
<span class="hljs-keyword">doneIf all 100 attempts return 200 or 401 without any throttling, rate limiting is missing.
Insecure password reset flow:
POST /api/reset-password HTTP/1.1
Host: app.example.com
Content-Type: application/json
{"email": "victim@example.com"}Then immediately try the reset token from your own email for the victim's account — this tests for token reuse and predictable tokens.
A05: Security Misconfiguration
Misconfiguration is the most widespread vulnerability category. It includes default credentials, overly permissive CORS, exposed stack traces, verbose error messages, and unnecessary HTTP methods enabled.
Test Cases
Verbose error messages — Send malformed input and look for stack traces:
GET /api/users/abc HTTP/1.1
Host: app.example.comIf the response includes a Java stack trace, Python traceback, or SQL query, the application is leaking implementation details.
CORS misconfiguration:
GET /api/profile HTTP/1.1
Host: app.example.com
Origin: https://evil.com
Authorization: Bearer <token>If the response includes Access-Control-Allow-Origin: https://evil.com, check whether cookies or credentials are also allowed. A wildcard origin with Access-Control-Allow-Credentials: true is a critical misconfiguration.
Unnecessary HTTP methods:
curl -X OPTIONS https://app.example.com/api/users -vThe response should not include TRACE or DELETE if those are not intended.
Tools
- Nikto: Scans for common misconfigurations
- OWASP ZAP: Checks security headers and CORS
- Shodan: Finds exposed services and default credentials
A06: Vulnerable and Outdated Components
Using components with known vulnerabilities is one of the easiest risks to mitigate and one of the most commonly ignored. This includes libraries, frameworks, databases, and OS packages.
Test Cases
Enumerate dependencies:
# Node.js
npm audit
<span class="hljs-comment"># Python
pip-audit
<span class="hljs-comment"># Java
mvn dependency-check:checkCheck CVEs for discovered versions:
# Find the version of a library from HTTP headers or response bodies
curl -I https://app.example.com <span class="hljs-pipe">| grep -i server
curl -I https://app.example.com <span class="hljs-pipe">| grep -i x-powered-byThen search the National Vulnerability Database (nvd.nist.gov) for known CVEs for that version.
Tools
- OWASP Dependency-Check: Scans Java, .NET, JavaScript
- Snyk: SaaS tool with GitHub integration
- Trivy: Container and filesystem vulnerability scanner
A07: Identification and Authentication Failures
This covers broken authentication — weak passwords, credential stuffing, missing MFA, insecure session tokens, and flawed "remember me" implementations.
Test Cases
Session token entropy — Capture a session token and analyze its structure:
Set-Cookie: sessionId=dXNlcjoxMjM0NTY=; Path=/; HttpOnlyBase64-decode it. If it encodes predictable data like a user ID, the token is insecure.
Missing HttpOnly and Secure flags:
HTTP/1.1 200 OK
Set-Cookie: session=abc123; Path=/Cookies without HttpOnly are accessible to JavaScript (XSS risk). Cookies without Secure are sent over HTTP.
Credential stuffing protection — Test whether the application allows rapid login attempts with different credential pairs without triggering lockout or CAPTCHA.
A08: Software and Data Integrity Failures
This category covers insecure deserialization, CI/CD pipeline attacks, and auto-update mechanisms that do not verify integrity. The Log4Shell vulnerability was partially an integrity failure — a library that blindly resolved remote content.
Test Cases
Insecure deserialization — Look for serialized objects in cookies, POST bodies, or headers:
Cookie: user=rO0ABXNyAA==rO0AB is the base64-encoded Java serialized object header. Try substituting a known gadget chain payload.
Content Security Policy for subresource integrity:
<!-- Secure -->
<script src="https://cdn.example.com/lib.js"
integrity="sha384-abc123..."
crossorigin="anonymous"></script>
<!-- Insecure - no integrity check -->
<script src="https://cdn.example.com/lib.js"></script>Check whether third-party scripts include integrity attributes.
A09: Security Logging and Monitoring Failures
You cannot detect or respond to attacks if you are not logging them. This category covers insufficient logging, missing alerting, and logs that do not contain enough information to reconstruct an attack.
Test Cases
Trigger security events and verify logging:
- Attempt to log in with invalid credentials 10 times
- Access a resource you should not have access to
- Submit clearly malicious payloads (
' OR 1=1 --)
Then check your SIEM or log management system. If these events did not generate alerts or are not visible in logs with IP, timestamp, and user ID, your logging is insufficient.
Log injection testing — Submit newline characters in input fields:
username=admin%0aINJECTED_LOG_LINEIf the injected line appears in logs, an attacker could forge log entries to cover their tracks.
A10: Server-Side Request Forgery (SSRF)
SSRF occurs when an application makes HTTP requests to a user-controlled URL. An attacker can use this to reach internal services, cloud metadata endpoints, or bypass firewalls.
Test Cases
Basic SSRF detection — Find any parameter that accepts a URL:
POST /api/fetch-preview HTTP/1.1
Host: app.example.com
Content-Type: application/json
{"url": "http://169.254.169.254/latest/meta-data/"}The AWS metadata endpoint (169.254.169.254) returns IAM credentials if the server is running on EC2 and SSRF is present.
Blind SSRF — Use an out-of-band detection server:
{"url": "http://your-burpcollaborator.net/ssrf-test"}If your Burp Collaborator or interactsh server receives a request, SSRF is confirmed even if the response is not returned to you.
Tools
- Burp Suite Pro: Built-in Collaborator for blind SSRF detection
- interactsh: Open-source alternative to Burp Collaborator
- SSRF-Sheriff: Specialized SSRF testing tool
Putting It All Together: A Testing Workflow
A complete OWASP Top 10 assessment should follow this workflow:
- Reconnaissance: Map all endpoints, parameters, and authentication mechanisms
- Automated scanning: Run OWASP ZAP or Burp Suite active scanner against all discovered endpoints
- Manual verification: Confirm every automated finding by hand — scanners produce false positives
- Manual testing for logic flaws: Access control, insecure design, and SSRF often require manual testing
- Component analysis: Run dependency scanners against all package manifests
- Reporting: Document every finding with reproduction steps, impact, and a recommended fix
OWASP ZAP Quick Start
# Install ZAP
docker pull ghcr.io/zaproxy/zaproxy:stable
<span class="hljs-comment"># Run baseline scan
docker run -t ghcr.io/zaproxy/zaproxy:stable zap-baseline.py \
-t https://app.example.com \
-r zap-report.html
<span class="hljs-comment"># Run full active scan
docker run -t ghcr.io/zaproxy/zaproxy:stable zap-full-scan.py \
-t https://app.example.com \
-r zap-full-report.htmlBurp Suite Essentials
Burp Suite intercepts all traffic between your browser and the target. Configure your browser to use Burp as a proxy (127.0.0.1:8080), then:
- Proxy > HTTP history: Review every request your application makes
- Scanner: Right-click any request → "Scan" to run active checks
- Repeater: Modify and replay requests manually
- Intruder: Fuzz parameters with wordlists
Integrating OWASP Testing Into CI/CD
Security testing should not be a once-a-year activity. Integrate it into your pipeline:
# GitHub Actions example
security-scan:
runs-on: ubuntu-latest
steps:
- name: Run OWASP ZAP
uses: zaproxy/action-baseline@v0.10.0
with:
target: 'https://staging.example.com'
fail_action: true
rules_file_name: '.zap/rules.tsv'For dependency scanning:
- name: Run npm audit
run: npm audit --audit-level=high
- name: Run Snyk
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}Summary
The OWASP Top 10 is a minimum baseline, not a ceiling. Testing against all 10 categories requires a combination of automated tools (ZAP, Burp, dependency scanners) and manual testing — especially for access control flaws, business logic issues, and SSRF. Build security testing into your CI/CD pipeline, run it against every release, and treat security findings with the same priority as functional bugs.
The most important thing is to start. Pick one category from this guide, test your application against it today, and build from there. A partially tested application is more secure than an untested one.