level 11 / owasp-top-10

OWASP Top 10 for Testers

Understand the OWASP Top 10 vulnerabilities and how test engineers detect them.

The OWASP Top 10 (2021)

OWASP (Open Web Application Security Project) publishes the most critical web security risks. Test engineers need awareness to write security-conscious tests and find common vulnerabilities.

#VulnerabilityQuick description
A01Broken Access ControlUsers can act outside their permissions
A02Cryptographic FailuresSensitive data exposed (no TLS, weak encryption)
A03InjectionSQL, OS, LDAP injection via untrusted input
A04Insecure DesignArchitecture-level security flaws
A05Security MisconfigurationDefault credentials, verbose errors, open ports
A06Vulnerable & Outdated ComponentsDependencies with known CVEs
A07Identification & Auth FailuresBroken auth, weak passwords, no MFA
A08Software & Data Integrity FailuresCI/CD pipeline tampering, unsigned packages
A09Security Logging & Monitoring FailuresNo audit trail, no alerting on attacks
A10SSRFServer-side request forgery via user-controlled URLs

A01: Broken Access Control Tests

test('regular user cannot access admin endpoint', async ({ request }) => {
  const userToken = await getUserToken(request);

  const res = await request.get('/api/admin/users', {
    headers: { Authorization: `Bearer ${userToken}` },
  });
  expect(res.status()).toBe(403);  // Forbidden — not 200 or 404
});

test('user cannot access another user data via ID manipulation', async ({ request }) => {
  const userAToken = await loginAs(request, 'user-a');
  const userBId = 'user-b-id';

  // Horizontal privilege escalation — should be blocked
  const res = await request.get(`/api/users/${userBId}/profile`, {
    headers: { Authorization: `Bearer ${userAToken}` },
  });
  expect(res.status()).toBe(403);
});

A05: Security Misconfiguration

test('server does not expose version info in headers', async ({ request }) => {
  const res = await request.get('/');
  const headers = res.headers();
  expect(headers['x-powered-by']).toBeUndefined();   // hides tech stack
  expect(headers['server']).not.toContain('Apache'); // hides version
});

test('no debug endpoints in production', async ({ request }) => {
  const debugEndpoints = ['/debug', '/phpinfo', '/.env', '/config.json', '/swagger'];
  for (const endpoint of debugEndpoints) {
    const res = await request.get(endpoint);
    expect([403, 404]).toContain(res.status());       // must not be 200
  }
});

A07: Authentication Failures

test('brute force protection activates after N attempts', async ({ request }) => {
  // Attempt 5 wrong logins
  for (let i = 0; i < 5; i++) {
    await request.post('/api/login', {
      data: { username: 'admin', password: 'wrong' },
    });
  }
  // 6th attempt should be rate-limited or locked
  const res = await request.post('/api/login', {
    data: { username: 'admin', password: 'wrong' },
  });
  expect([429, 423]).toContain(res.status());   // Too Many Requests or Locked
});

test('password reset token expires', async ({ request }) => {
  // Generate token
  await request.post('/api/auth/reset-password', { data: { email: 'user@test.com' } });
  const token = await getLatestResetToken();   // from DB or email mock

  // Wait past expiry
  await new Promise(r => setTimeout(r, 2000));

  // Use an already-expired token (short expiry in test env)
  const res = await request.post('/api/auth/reset-password/confirm', {
    data: { token, newPassword: 'NewPass123!' },
  });
  expect(res.status()).toBe(400);   // expired token rejected
});

A02: Cryptographic Failures

test('login uses HTTPS', async ({ page }) => {
  const responses: string[] = [];
  page.on('response', (r) => responses.push(r.url()));

  await page.goto('/login');
  await page.fill('[name=email]', 'test@test.com');
  await page.fill('[name=password]', 'pass');
  await page.click('[type=submit]');

  // All network requests during login should use HTTPS
  const httpRequests = responses.filter(u => u.startsWith('http://'));
  expect(httpRequests).toHaveLength(0);
});

test('sensitive data not in URL parameters', async ({ page }) => {
  await page.goto('/login');
  // Login...
  const url = page.url();
  // No token in URL (visible in browser history, logs, referrer headers)
  expect(url).not.toContain('token=');
  expect(url).not.toContain('password=');
});

Security Testing Tools

ToolPurpose
OWASP ZAPAutomated scanner — integrates with Playwright
Burp SuiteManual + automated web app pen testing
SnykDependency vulnerability scanning
TrivyContainer image scanning
SemGrepStatic analysis for security patterns
OWASP Dependency-CheckKnown CVE checking in dependencies