OWASP Top 10 Testing Checklist: How to Test Each Vulnerability
The OWASP Top 10 is the most referenced list in web application security. Published by the Open Web Application Security Project, it represents the ten most critical security risks based on data from thousands of real-world applications.
This checklist gives you concrete tests for each category — not just definitions, but actual test cases you can run against your application.
How to Use This Checklist
For each category:
- Identify where your application is potentially exposed
- Run the listed test cases
- Verify each remediation is actually in place — don't assume
Mark each item as:
- ✅ Tested and secure
- ❌ Vulnerable — needs fix
- ⏭ Not applicable to this application
A01: Broken Access Control
The #1 risk. Users doing things they shouldn't be able to do.
Test cases:
□ Change your user ID in API requests to another user's ID
GET /api/users/1001/profile → change to /api/users/1002/profile
Expected: 403 Forbidden
Fail: returns user 1002's data
□ Access admin pages while logged in as a regular user
GET /admin/dashboard
Expected: 403 or redirect to login
Fail: admin panel loads
□ Skip steps in a multi-step workflow
Go directly to /checkout/confirm without completing /checkout/payment
Expected: redirect back or error
Fail: order completes without payment
□ Access another user's files by guessing filenames
GET /files/user-1001/invoice.pdf → try /files/user-1002/invoice.pdf
Expected: 403
Fail: file downloads
□ Test force browsing for unlinked admin/debug endpoints
Try: /admin, /debug, /api-docs, /actuator, /metrics, /.git
Expected: 404 or 403
Fail: page loads with sensitive data
□ Modify hidden form fields
Find a hidden input with a user ID or role — change it before submitting
Expected: server ignores the field or rejects the request
Fail: server uses the modified valueWhat to look for: The server must enforce authorization on every request. Client-side hiding (hiding an admin button in the UI) is not access control.
A02: Cryptographic Failures
Sensitive data exposed due to weak encryption, missing encryption, or implementation errors.
Test cases:
□ Check all traffic is HTTPS
Open DevTools Network tab — look for any HTTP requests
Expected: all requests use HTTPS
Fail: any sensitive data transmitted over HTTP
□ Check HSTS header
curl -I https://example.com | grep Strict-Transport-Security
Expected: Strict-Transport-Security: max-age=31536000; includeSubDomains
Fail: header missing
□ Look for sensitive data in URL parameters
Search HTTP history for: password=, token=, key=, secret= in URL
Expected: none
Fail: sensitive values in URLs (logged by servers, browsers, CDNs)
□ Check for sensitive data in local storage / cookies
DevTools → Application → Local Storage / Session Storage / Cookies
Expected: no plaintext passwords or private tokens stored client-side
Fail: sensitive values visible
□ Check cookie security flags
Inspect Set-Cookie headers
Expected: Secure; HttpOnly; SameSite=Strict (or Lax)
Fail: missing flags (especially Secure and HttpOnly on auth cookies)
□ Check if old SSL/TLS versions are accepted
testssl.sh example.com
Expected: only TLS 1.2+ accepted
Fail: TLS 1.0/1.1 or SSL accepted
□ Check for secrets in client-side JS
View page source and JS bundles — search for: api_key, secret, password, token
Expected: none
Fail: credentials hardcoded in sourceA03: Injection
Untrusted data sent to an interpreter — SQL, OS commands, LDAP, etc.
Test cases:
□ SQL Injection — basic
Append ' to any parameter: ?id=1'
Expected: normal response or generic error
Fail: database error message visible
□ SQL Injection — boolean-based
?id=1 AND 1=1-- vs ?id=1 AND 1=2--
Expected: same response
Fail: different responses indicate injectable parameter
□ SQL Injection — automated
sqlmap -u "https://example.com/items?id=1" --level=2
Expected: no injections found
Fail: sqlmap extracts database content
□ Command Injection
In any input that might reach the OS (file name, IP address field, etc.):
test; whoami
test && id
test | ls
Expected: no command output in response
Fail: command output visible
□ LDAP Injection (if LDAP auth is used)
Username: admin)(|(password=*)
Expected: authentication fails
Fail: bypass or LDAP error visible
□ XPath Injection (if XML used internally)
' or '1'='1
Expected: normal behavior
Fail: query returns unexpected results or error
□ Template Injection
In any template-rendered input (name fields, email templates, etc.):
{{7*7}} or ${7*7} or <%= 7*7 %>
Expected: literal text rendered, not 49
Fail: 49 appears — template is evaluating inputA04: Insecure Design
Missing security controls in the application architecture itself.
Test cases:
□ Check password reset flow
Request reset → check if token is predictable (sequential, timestamp-based)
Expected: high-entropy random token
Fail: predictable pattern
□ Check token expiry
Request a password reset token → wait 24 hours → try to use it
Expected: token expired / invalid
Fail: old token still works
□ Check one-time token reuse
Use a password reset link → try to use it again
Expected: link is invalid after first use
Fail: link works multiple times
□ Account enumeration on password reset
Enter a registered email → note response message
Enter a non-registered email → note response message
Expected: identical responses
Fail: different responses reveal whether email is registered
□ Check rate limiting on sensitive actions
Attempt login 50 times rapidly
Expected: lockout, CAPTCHA, or progressive delay after N failures
Fail: unlimited attempts allowed
□ Business logic — skip workflow steps
Multi-step checkout: go directly to confirmation step URL
Expected: server validates previous steps completed
Fail: order completes without paymentA05: Security Misconfiguration
Insecure default configurations, incomplete setup, open cloud storage, verbose errors.
Test cases:
□ Check for verbose error messages
Cause an error (wrong type parameter, missing required field)
Expected: generic error message ("Something went wrong")
Fail: stack traces, file paths, or database errors visible
□ Check for default credentials
Try: admin/admin, admin/password, root/root, test/test
Expected: all fail
Fail: any default credential works
□ Check security headers
curl -I https://example.com
Expected headers: Content-Security-Policy, X-Frame-Options,
X-Content-Type-Options, Referrer-Policy, Permissions-Policy
Fail: missing security headers
□ Check for exposed admin interfaces
Try: /admin, /phpmyadmin, /adminer, /.env, /config.php
Expected: 403 or 404
Fail: admin interfaces publicly accessible
□ Check for exposed .git directory
curl https://example.com/.git/HEAD
Expected: 404
Fail: "ref: refs/heads/main" returned — source code accessible
□ Check CORS configuration
curl -H "Origin: https://evil.com" -I https://example.com/api/data
Expected: no Access-Control-Allow-Origin: * on sensitive endpoints
Fail: wildcard CORS allows any origin to read your API
□ Check for directory listing
Navigate to a directory (e.g., /uploads/)
Expected: 403 or 404
Fail: file listing displayedA06: Vulnerable and Outdated Components
Using libraries, frameworks, or components with known vulnerabilities.
Test cases:
□ Scan dependencies for known vulnerabilities
npm audit --audit-level=moderate
pip-audit
bundler-audit
Expected: no critical/high vulnerabilities
Fail: unpatched CVEs in dependencies
□ Check for outdated server software in response headers
curl -I https://example.com | grep -i server
Check version against CVE database
Expected: either no version exposed or current version
Fail: old versions with known CVEs
□ Check WordPress/CMS plugin versions (if applicable)
wpscan --url https://example.com
Expected: all plugins and themes up to date
Fail: outdated plugins with known exploits
□ Check for abandoned packages
npm outdated → look for packages with no recent updates
Research if abandoned packages have unpatched security issues
□ Run automated scanner against known vulnerability signatures
nuclei -u https://example.com -t nuclei-templates/cves/
Expected: no CVE matches
Fail: known CVEs detectedA07: Identification and Authentication Failures
Broken authentication, weak passwords, session management flaws.
Test cases:
□ Check password policy
Create account with: password123, 12345678, qwerty, abc123
Expected: all rejected as too weak
Fail: weak passwords accepted
□ Check against known breached passwords
Try: "password", "123456", "letmein" (top 10 breached passwords)
Expected: rejected
Fail: common passwords accepted
□ Check brute force protection on login
Submit 20 wrong passwords rapidly
Expected: lockout or CAPTCHA after N failures
Fail: unlimited attempts
□ Check session token entropy
Log in 10 times → collect all session tokens
Look for patterns (sequential, timestamp-based, base64-encoded user data)
Expected: high-entropy random tokens, no patterns
Fail: predictable tokens
□ Check session invalidation on logout
Log in → capture session token → log out → use the old token
Expected: 401 Unauthorized
Fail: old session still works
□ Check session invalidation on password change
Log in on two devices → change password on device 1 → try to use device 2's session
Expected: device 2 logged out
Fail: old session still active after password change
□ Check "Remember Me" implementation
Enable remember me → inspect the persistent cookie
Expected: opaque random token stored server-side
Fail: user ID or other identifying info encoded in cookie
□ Multi-factor authentication bypass
If MFA is available: complete step 1 (password), skip to authenticated URL
Expected: redirected back to MFA prompt
Fail: MFA bypassedA08: Software and Data Integrity Failures
Code and infrastructure that doesn't verify integrity — insecure deserialization, compromised CI/CD.
Test cases:
□ Check for insecure deserialization
Find any endpoint that accepts serialized data (look for base64-encoded data,
Java serialized objects starting with "rO0", pickle data)
Attempt deserialization gadget chain attacks
Expected: input rejected or handled safely
Fail: code execution or unexpected behavior
□ Check auto-update mechanisms
Does the app auto-update without signature verification?
Expected: updates verified with cryptographic signature
Fail: updates downloaded and executed without verification
□ Inspect CI/CD pipeline for supply chain risks
Are third-party actions pinned by hash in GitHub Actions?
Expected: uses: actions/checkout@v4 with SHA pin
Fail: uses: some-third-party/action@latest (mutable reference)
□ Check Content Security Policy for unsafe-inline
curl -I https://example.com | grep Content-Security-Policy
Expected: no unsafe-inline or unsafe-eval directives
Fail: CSP allows inline scripts (XSS mitigation bypassed)A09: Security Logging and Monitoring Failures
Not detecting, escalating, or alerting on active attacks.
Test cases:
□ Check if login failures are logged
Attempt 10 failed logins → check if security team gets alerted
Expected: alerts triggered, attempts logged
Fail: no logging or alerting
□ Check if admin actions are audited
As admin: delete a user, change permissions, export data
Expected: all actions logged with user, timestamp, and action
Fail: no audit trail
□ Check log content for sensitive data
Review logs — do they contain plaintext passwords, credit cards, or PII?
Expected: sensitive data masked or excluded from logs
Fail: raw passwords or PII in log files
□ Verify logs can't be tampered with
Can a regular user (or attacker with limited access) modify log files?
Expected: logs written to append-only store, separate from app
Fail: logs on same filesystem, writable by app process
□ Check for alerting on impossible travel / anomalous logins
Log in from location A, then immediately from location B (different IP)
Expected: alert or challenge triggered
Fail: no detection of anomalous behaviorA10: Server-Side Request Forgery (SSRF)
Tricking the server into making HTTP requests to internal systems.
Test cases:
□ Test URL parameters that fetch external content
Find features like: link preview, webhook URL, image import by URL, PDF generation
Inject internal URLs:
http://localhost/
http://127.0.0.1/admin
http://169.254.169.254/latest/meta-data/ (AWS metadata)
http://10.0.0.1/
Expected: request blocked or whitelisted domains only
Fail: response contains internal system content
□ Test for blind SSRF
Use a callback URL you control (Burp Collaborator, webhook.site):
https://your-callback.burpcollaborator.net/
Expected: no outbound request from server
Fail: server makes request to your callback URL
□ Check URL parsing edge cases
http://evil.com@internal.example.com/
http://internal.example.com#@evil.com/
Expected: all treated correctly (no bypass)
Fail: URL validation bypassed, internal request made
□ Test DNS rebinding (advanced)
If URL validation is done at request time, check if it's also done at connection time
Expected: validation not bypassable via DNS rebinding
Fail: SSRF possible through DNS rebindingKeeping the Checklist Current
OWASP updates the Top 10 periodically (current version: 2021). The categories shift as the threat landscape changes. Keep testing:
- After every major feature addition
- Before every production release
- As part of your CI/CD pipeline (automated checks for A06, A05)
- During dedicated security review sprints (manual checks for all 10)
For automation, see our guide on automated security testing in CI pipelines. For a deeper dive on tooling, see the Burp Suite tutorial for QA teams.
HelpMeTest can help you run continuous functional tests that cover authentication, authorization, and session management scenarios — catching regressions before they become security incidents.