Knowing the OWASP Top 10 categories gives you awareness. Writing specific test cases for each vulnerability gives you detection capability. This lesson provides concrete, executable test cases for the four most common web application vulnerabilities: Cross-Site Scripting (XSS), SQL Injection, Cross-Site Request Forgery (CSRF), and authentication flaws. These test cases can be added to your existing functional test suite with minimal effort.
Targeted Test Cases for Common Vulnerabilities
Each vulnerability has specific input patterns that reveal whether the application is protected.
# ── XSS (Cross-Site Scripting) Test Cases ──
XSS_TESTS = [
{
"test": "Reflected XSS in search field",
"input": '',
"where": "Search bar, URL query parameters",
"pass_criteria": "Input is escaped or stripped; no script execution; "
"displayed as plain text, not rendered as HTML",
"check": "View page source — the script tag should be HTML-encoded: "
"<script> not ",
"where": "Any page that reflects URL parameters in the page content",
"pass_criteria": "Parameter is sanitised before rendering in the page",
},
]
# ── SQL Injection Test Cases ──
SQL_INJECTION_TESTS = [
{
"test": "SQL injection in login form",
"input_username": "' OR 1=1 --",
"input_password": "anything",
"pass_criteria": "Login fails with normal error message; no authentication bypass; "
"no database error messages exposed",
},
{
"test": "SQL injection in search field",
"input": "'; DROP TABLE products; --",
"pass_criteria": "Search returns zero results or an error; database is not affected; "
"no SQL error messages visible to the user",
},
{
"test": "SQL injection in URL parameters",
"input": "/api/products?category=electronics' UNION SELECT * FROM users --",
"pass_criteria": "API returns 400 Bad Request or empty results; "
"no data from other tables is leaked",
},
]
# ── CSRF Test Cases ──
CSRF_TESTS = [
{
"test": "State-changing request without CSRF token",
"method": "Intercept a POST/PUT/DELETE request; remove the CSRF token from the request",
"pass_criteria": "Server rejects the request with 403 Forbidden",
},
{
"test": "CSRF token reuse",
"method": "Capture a CSRF token from one session; use it in a different session",
"pass_criteria": "Server rejects the token; each session has unique tokens",
},
]
# ── Authentication Flaw Test Cases ──
AUTH_TESTS = [
{
"test": "Session persistence after logout",
"steps": "Login, copy the session cookie, logout, replay the cookie in a new request",
"pass_criteria": "Server rejects the old session cookie; returns 401 Unauthorized",
},
{
"test": "Session fixation",
"steps": "Note the session ID before login; login; check if the session ID changed",
"pass_criteria": "Session ID changes after authentication (new session created)",
},
{
"test": "Password reset information leakage",
"steps": "Request password reset for a valid and an invalid email",
"pass_criteria": "Same response for both — attacker cannot determine which emails exist",
},
{
"test": "Brute force protection",
"steps": "Submit 20 incorrect login attempts rapidly",
"pass_criteria": "Account is locked or rate-limited after 5-10 failed attempts; "
"CAPTCHA or delay is introduced",
},
]
print("XSS Test Cases:")
for t in XSS_TESTS:
print(f"\n {t['test']}")
print(f" Input: {t['input']}")
print(f" Pass: {t['pass_criteria']}")
print("\n\nSQL Injection Test Cases:")
for t in SQL_INJECTION_TESTS:
print(f"\n {t['test']}")
print(f" Pass: {t['pass_criteria']}")
print("\n\nAuthentication Test Cases:")
for t in AUTH_TESTS:
print(f"\n {t['test']}")
print(f" Pass: {t['pass_criteria']}")
<script>alert("XSS")</script> in any input field, submit, and check if the script executes. If you see an alert popup, the application is vulnerable. If the input appears as plain text (HTML-encoded), the application is protected. This single test, applied to every input field in the application, catches the most common form of reflected XSS. It takes 10 seconds per field and can be automated by parameterising your existing input validation tests with adversarial payloads.@pytest.mark.parametrize("input", [normal_data, xss_payload, sql_payload]).'; DROP TABLE products; -- could actually drop the products table if the application does not sanitise inputs. Always run security tests against dedicated test environments with expendable data. Never test SQL injection against production or shared staging databases.Common Mistakes
Mistake 1 — Testing XSS only in visible form fields
❌ Wrong: Testing only the search bar and registration form for XSS — missing hidden fields, URL parameters, and API request bodies.
✅ Correct: Testing every input vector: form fields, URL query parameters, HTTP headers (User-Agent, Referer), file upload names, and API request bodies. XSS can be injected through any input the application processes.
Mistake 2 — Accepting "the framework handles security" as sufficient
❌ Wrong: "We use React, which auto-escapes output. We do not need XSS testing."
✅ Correct: "React auto-escapes JSX output, but dangerouslySetInnerHTML, href attributes with javascript: URLs, and server-rendered HTML bypass this protection. We test every input regardless of framework claims."