Security Testing for QA Engineers
Security testing is not just for penetration testers. QA engineers encounter security-relevant features daily: login forms, user input fields, API endpoints, and file uploads. Understanding common vulnerabilities and how to test for them makes you a more effective tester and helps prevent security breaches.
This lesson focuses on practical, hands-on security testing that QA engineers can perform without specialized tools.
The OWASP Top 10
The OWASP Top 10 is the most widely referenced list of web application security risks. The most relevant for QA testing:
| Risk | Description | QA Testing Approach |
|---|---|---|
| Injection (SQL, XSS) | Untrusted data sent to interpreter | Test input fields with special characters |
| Broken Authentication | Flawed login, session, password reset | Test auth flows thoroughly |
| Sensitive Data Exposure | Unencrypted sensitive data | Check HTTPS, headers, storage |
| Broken Access Control | Users accessing unauthorized resources | Test role-based access |
| Security Misconfiguration | Default configs, verbose errors | Check error pages, headers |
| Cross-Site Scripting (XSS) | Malicious script injection | Test all user inputs |
| CSRF | Unwanted authenticated requests | Verify CSRF tokens |
Cross-Site Scripting (XSS) Testing
Types of XSS
| Type | How It Works | Persistence |
|---|---|---|
| Reflected | Payload in URL parameter, reflected in response | Not stored |
| Stored | Payload saved in database, shown to all users | Persistent |
| DOM-based | Payload manipulates client-side JavaScript | Client-side only |
Basic XSS Test Payloads
Test these in every input field, search box, URL parameter, and user profile field:
<script>alert('XSS')</script>
"><script>alert('XSS')</script>
<img src=x onerror=alert('XSS')>
<svg onload=alert('XSS')>
javascript:alert('XSS')
" onfocus="alert('XSS')" autofocus="
If any of these trigger a JavaScript alert, the application is vulnerable.
Where to Test for XSS
- Search boxes (reflected in search results)
- Comment/review fields (stored XSS)
- User profile fields (name, bio, website URL)
- URL parameters (
?q=<script>alert(1)</script>) - File upload names
- Error messages that reflect user input
CSRF Testing
How CSRF Works
- User is logged into
bank.com - User visits malicious
evil.com evil.comhas a hidden form that submits tobank.com/transfer?to=attacker&amount=1000- Browser automatically includes bank.com cookies
- Transfer executes without user’s knowledge
Testing for CSRF Protection
- Find a state-changing action (change password, update profile, delete item)
- Inspect the form — look for a hidden CSRF token field
- Submit the form normally — it should work
- Remove or modify the CSRF token — the request should be rejected
- Replay the request from a different origin — it should be rejected
<!-- Check for CSRF token in forms -->
<form action="/api/change-password" method="POST">
<input type="hidden" name="_csrf" value="abc123token">
<!-- Without this token, the server should reject the request -->
</form>
SQL Injection Testing
Basic SQL Injection Payloads
Test in login forms, search fields, and URL parameters:
' OR '1'='1
' OR '1'='1' --
' UNION SELECT NULL--
'; DROP TABLE users--
1 OR 1=1
If any of these produce unexpected behavior (login bypass, error with SQL syntax, extra data), the application may be vulnerable.
Note: Modern frameworks with parameterized queries largely prevent SQL injection. However, custom queries and legacy code may still be vulnerable.
Security Headers Testing
Check that security-related HTTP headers are set:
curl -I https://example.com
| Header | Expected Value | Purpose |
|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains | Force HTTPS |
X-Content-Type-Options | nosniff | Prevent MIME sniffing |
X-Frame-Options | DENY or SAMEORIGIN | Prevent clickjacking |
Content-Security-Policy | Restrictive policy | Prevent XSS, data injection |
X-XSS-Protection | 0 (rely on CSP instead) | Legacy XSS filter |
Referrer-Policy | strict-origin-when-cross-origin | Control referrer info |
Sensitive Data Testing
- No passwords visible in page source or network requests
- Credit card numbers masked in UI and logs
- Session tokens not in URL parameters (use cookies with HttpOnly and Secure flags)
- No sensitive data in browser localStorage (check Application tab)
- API responses do not include unnecessary sensitive fields
Exercise: Web Security Audit
Perform a security-focused test of a web application’s authentication and user input handling.
Part 1: XSS Testing
Test 5 input fields with XSS payloads:
| Input Location | Payload Used | Rendered? Executed? | Vulnerable? |
|---|---|---|---|
| Search box | <script>alert(1)</script> | ||
| Profile name | <img src=x onerror=alert(1)> | ||
| Comment field | <svg onload=alert(1)> | ||
| URL parameter | ?q="><script>alert(1)</script> | ||
| Contact form | " onfocus="alert(1)" autofocus |
Part 2: CSRF Testing
| Test | Expected | Result |
|---|---|---|
| Form has CSRF token | Token present in hidden field | |
| Submit with valid token | Request succeeds | |
| Submit with empty token | Request rejected (403) | |
| Submit with modified token | Request rejected | |
| Replay request from different tab | Request rejected |
Part 3: Security Headers
curl -I https://your-site.com
| Header | Present? | Value | Correct? |
|---|---|---|---|
| Strict-Transport-Security | |||
| X-Content-Type-Options | |||
| X-Frame-Options | |||
| Content-Security-Policy | |||
| Referrer-Policy |
Part 4: Authentication Security
| Test | Expected | Result |
|---|---|---|
| Login with SQL injection payload | Login fails normally | |
| Failed login does not reveal if email exists | Generic error message | |
| Session expires after inactivity | Session invalid after timeout | |
| Password reset token is one-time use | Cannot reuse token | |
| Session cookie has HttpOnly flag | Cookie not accessible via JS | |
| Session cookie has Secure flag | Cookie only sent over HTTPS |
Solution: Common Security Findings
Finding 1: Reflected XSS in search
The search box reflected user input without encoding. Payload <script>alert(1)</script> executed. Fix: HTML-encode all user input before rendering.
Finding 2: Missing CSRF token on profile update The profile update form had no CSRF protection. An attacker could change a user’s email by embedding a hidden form on another site. Fix: Add CSRF token to all state-changing forms.
Finding 3: Missing security headers No Content-Security-Policy header, allowing inline scripts (XSS vector). No Strict-Transport-Security, allowing HTTPS downgrade. Fix: Add security headers to all responses.
Finding 4: Session cookie missing HttpOnly
Session cookie accessible via document.cookie in browser console. An XSS attack could steal the session. Fix: Set HttpOnly flag on session cookies.
Finding 5: Verbose error messages SQL errors displayed on login when using special characters. Revealed database type and table structure. Fix: Return generic error messages, log details server-side.
Security Testing Tools for QA
| Tool | Purpose | Complexity |
|---|---|---|
| Browser DevTools | Header inspection, cookie analysis | Low |
| OWASP ZAP | Automated vulnerability scanner | Medium |
| Burp Suite Community | HTTP proxy for request manipulation | Medium |
| SecurityHeaders.com | Quick header check | Low |
| Mozilla Observatory | Comprehensive security scan | Low |
Key Takeaways
- QA engineers can and should perform basic security testing on every feature
- Test all user inputs for XSS — search boxes, profile fields, comments, URL parameters
- Verify CSRF protection on every state-changing action (forms, API calls)
- Check security headers with curl or browser DevTools on every deployment
- Never expose technical details in error messages — they help attackers
- Session cookies must have HttpOnly and Secure flags
- Use the OWASP Top 10 as a checklist for security-focused test planning