Secure Coding Guide for Web Applications skill

This skill helps Claude write secure web applications.

by BehiSecc·Apache-2.0 license·★ 1,309 Stars on the repo·GitHub ↗

Use now

Files of Secure Coding Guide for Web Applications

BehiSecc/main1 file
SKILL.md
Show the full text759 lines

Secure Coding Guide for Web Applications

Overview

This guide provides comprehensive secure coding practices for web applications. As an AI assistant, your role is to approach code from a bug hunter's perspective and make applications as secure as possible without breaking functionality.

Key Principles:

  • Defense in depth: Never rely on a single security control
  • Fail securely: When something fails, fail closed (deny access)
  • Least privilege: Grant minimum permissions necessary
  • Input validation: Never trust user input, validate everything server-side
  • Output encoding: Encode data appropriately for the context it's rendered in

Access Control Issues

Access control vulnerabilities occur when users can access resources or perform actions beyond their intended permissions.

Core Requirements

For every data point and action that requires authentication:

  1. User-Level Authorization

    • Each user must only access/modify their own data
    • No user should access data from other users or organizations
    • Always verify ownership at the data layer, not just the route level
  2. Use UUIDs Instead of Sequential IDs

    • Use UUIDv4 or similar non-guessable identifiers
    • Exception: Only use sequential IDs if explicitly requested by user
  3. Account Lifecycle Handling

    • When a user is removed from an organization: immediately revoke all access tokens and sessions
    • When an account is deleted/deactivated: invalidate all active sessions and API keys
    • Implement token revocation lists or short-lived tokens with refresh mechanisms
Authorization Checks Checklist
  • Verify user owns the resource on every request (don't trust client-side data)
  • Check organization membership for multi-tenant apps
  • Validate role permissions for role-based actions
  • Re-validate permissions after any privilege change
  • Check parent resource ownership (e.g., if accessing a comment, verify user owns the parent post)
Common Pitfalls to Avoid
  • IDOR (Insecure Direct Object Reference): Always verify the requesting user has permission to access the requested resource ID
  • Privilege Escalation: Validate role changes server-side; never trust role info from client
  • Horizontal Access: User A accessing User B's resources with the same privilege level
  • Vertical Access: Regular user accessing admin functionality
  • Mass Assignment: Filter which fields users can update; don't blindly accept all request body fields
Implementation Pattern
# Pseudocode for secure resource access
function getResource(resourceId, currentUser):
    resource = database.find(resourceId)
    
    if resource is null:
        return 404  # Don't reveal if resource exists
    
    if resource.ownerId != currentUser.id:
        if not currentUser.hasOrgAccess(resource.orgId):
            return 404  # Return 404, not 403, to prevent enumeration
    
    return resource

Client-Side Bugs

Cross-Site Scripting (XSS)

Every input controllable by the user—whether directly or indirectly—must be sanitized against XSS.

Input Sources to Protect

Direct Inputs:

  • Form fields (email, name, bio, comments, etc.)
  • Search queries
  • File names during upload
  • Rich text editors / WYSIWYG content

Indirect Inputs:

  • URL parameters and query strings
  • URL fragments (hash values)
  • HTTP headers used in the application (Referer, User-Agent if displayed)
  • Data from third-party APIs displayed to users
  • WebSocket messages
  • postMessage data from iframes
  • LocalStorage/SessionStorage values if rendered

Often Overlooked:

  • Error messages that reflect user input
  • PDF/document generators that accept HTML
  • Email templates with user data
  • Log viewers in admin panels
  • JSON responses rendered as HTML
  • SVG file uploads (can contain JavaScript)
  • Markdown rendering (if allowing HTML)
Protection Strategies
  1. Output Encoding (Context-Specific)

    • HTML context: HTML entity encode (< → &lt;)
    • JavaScript context: JavaScript escape
    • URL context: URL encode
    • CSS context: CSS escape
    • Use framework's built-in escaping (React's JSX, Vue's {{ }}, etc.)
  2. Content Security Policy (CSP)

    Content-Security-Policy: 
      default-src 'self';
      script-src 'self';
      style-src 'self' 'unsafe-inline';
      img-src 'self' data: https:;
      font-src 'self';
      connect-src 'self' https://api.yourdomain.com;
      frame-ancestors 'none';
      base-uri 'self';
      form-action 'self';
    
    • Avoid 'unsafe-inline' and 'unsafe-eval' for scripts
    • Use nonces or hashes for inline scripts when necessary
    • Report violations: report-uri /csp-report
  3. Input Sanitization

    • Use established libraries (DOMPurify for HTML)
    • Whitelist allowed tags/attributes for rich text
    • Strip or encode dangerous patterns
  4. Additional Headers

    • X-Content-Type-Options: nosniff
    • X-Frame-Options: DENY (or use CSP frame-ancestors)

Cross-Site Request Forgery (CSRF)

Every state-changing endpoint must be protected against CSRF attacks.

Endpoints Requiring CSRF Protection

Authenticated Actions:

  • All POST, PUT, PATCH, DELETE requests
  • Any GET request that changes state (fix these to use proper HTTP methods)
  • File uploads
  • Settings changes
  • Payment/transaction endpoints

Pre-Authentication Actions:

  • Login endpoints (prevent login CSRF)
  • Signup endpoints
  • Password reset request endpoints
  • Password change endpoints
  • Email/phone verification endpoints
  • OAuth callback endpoints
Protection Mechanisms
  1. CSRF Tokens

    • Generate cryptographically random tokens
    • Tie token to user session
    • Validate on every state-changing request
    • Regenerate after login (prevent session fixation combo)
  2. SameSite Cookies

    Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
    
    • Strict: Cookie never sent cross-site (best security)
    • Lax: Cookie sent on top-level navigations (good balance)
    • Always combine with CSRF tokens for defense in depth
  3. Double Submit Cookie Pattern

    • Send CSRF token in both cookie and request body/header
    • Server validates they match
Edge Cases and Common Mistakes
  • Token presence check: CSRF validation must NOT depend on whether the token is present, always require it
  • Token per form: Consider unique tokens per form for sensitive operations
  • JSON APIs: Don't assume JSON content-type prevents CSRF; validate Origin/Referer headers AND use tokens
  • CORS misconfiguration: Overly permissive CORS can bypass SameSite cookies
  • Subdomains: CSRF tokens should be scoped because subdomain takeover can lead to CSRF
  • Flash/PDF uploads: Legacy browser plugins could bypass SameSite
  • GET requests with side effects: Never perform state changes on GET
  • Token leakage: Don't include CSRF tokens in URLs
  • Token in URL vs Header: Prefer custom headers (X-CSRF-Token) over URL parameters
Verification Checklist
  • Token is cryptographically random (use secure random generator)
  • Token is tied to user session
  • Token is validated server-side on all state-changing requests
  • Missing token = rejected request
  • Token regenerated on authentication state change
  • SameSite cookie attribute is set
  • Secure and HttpOnly flags on session cookies

Secret Keys and Sensitive Data Exposure

No secrets or sensitive information should be accessible to client-side code.

Never Expose in Client-Side Code

API Keys and Secrets:

  • Third-party API keys (Stripe, AWS, etc.)
  • Database connection strings
  • JWT signing secrets
  • Encryption keys
  • OAuth client secrets
  • Internal service URLs/credentials

Sensitive User Data:

  • Full credit card numbers
  • Social Security Numbers
  • Passwords (even hashed)
  • Security questions/answers
  • Full phone numbers (mask them: --1234)
  • Sensitive PII that isn't needed for display

Infrastructure Details:

  • Internal IP addresses
  • Database schemas
  • Debug information
  • Stack traces in production
  • Server software versions
Where Secrets Hide (Check These!)
  • JavaScript bundles (including source maps)
  • HTML comments
  • Hidden form fields
  • Data attributes
  • LocalStorage/SessionStorage
  • Initial state/hydration data in SSR apps
  • Environment variables exposed via build tools (NEXT_PUBLIC_*, REACT_APP_*)
Best Practices
  1. Environment Variables: Store secrets in .env files
  2. Server-Side Only: Make API calls requiring secrets from backend only

Open Redirect

Any endpoint accepting a URL for redirection must be protected against open redirect attacks.

Protection Strategies
  1. Allowlist Validation

    allowed_domains = ['yourdomain.com', 'app.yourdomain.com']
    
    function isValidRedirect(url):
        parsed = parseUrl(url)
        return parsed.hostname in allowed_domains
    
  2. Relative URLs Only

    • Only accept paths (e.g., /dashboard) not full URLs
    • Validate the path starts with / and doesn't contain //
  3. Indirect References

    • Use a mapping instead of raw URLs: ?redirect=dashboard → lookup to /dashboard
Bypass Techniques to Block
Technique Example Why It Works
@ symbol https://[email protected] Browser navigates to evil.com with legit.com as username
Subdomain abuse https://legit.com.evil.com evil.com owns the subdomain
Protocol tricks javascript:alert(1) XSS via redirect
Double URL encoding %252f%252fevil.com Decodes to //evil.com after double decode
Backslash https://legit.com\@evil.com Some parsers normalize \ to /
Null byte https://legit.com%00.evil.com Some parsers truncate at null
Tab/newline https://legit.com%09.evil.com Whitespace confusion
Unicode normalization https://legіt.com (Cyrillic і) IDN homograph attack
Data URLs data:text/html,<script>... Direct payload execution
Protocol-relative //evil.com Uses current page's protocol
Fragment abuse https://legit.com#@evil.com Parsed differently by different libraries
IDN Homograph Attack Protection
  • Convert URLs to Punycode before validation
  • Consider blocking non-ASCII domains entirely for sensitive redirects

Password Security
Password Requirements
  • Minimum 8 characters (12+ recommended)
  • No maximum length (or very high, e.g., 128 chars)
  • Allow all characters including special chars
  • Don't require specific character types (let users choose strong passwords)
Storage
  • Use Argon2id, bcrypt, or scrypt
  • Never MD5, SHA1, or plain SHA256

Server-Side Bugs

Server-Side Request Forgery (SSRF)

Any functionality where the server makes requests to URLs provided or influenced by users must be protected.

Potential Vulnerable Features
  • Webhooks (user provides callback URL)
  • URL previews
  • PDF generators from URLs
  • Image/file fetching from URLs
  • Import from URL features
  • RSS/feed readers
  • API integrations with user-provided endpoints
  • Proxy functionality
  • HTML to PDF/image converters
Protection Strategies
  1. Allowlist Approach (Preferred)

    • Only allow requests to pre-approved domains
    • Maintain a strict allowlist for integrations
  2. Network Segmentation

    • Run URL-fetching services in isolated network
    • Block access to internal network, cloud metadata
IP and DNS Bypass Techniques to Block
Technique Example Description
Decimal IP http://2130706433 127.0.0.1 as decimal
Octal IP http://0177.0.0.1 Octal representation
Hex IP http://0x7f.0x0.0x0.0x1 Hexadecimal
IPv6 localhost http://[::1] IPv6 loopback
IPv6 mapped IPv4 http://[::ffff:127.0.0.1] IPv4-mapped IPv6
Short IPv6 http://[::] All zeros
DNS rebinding Attacker's DNS returns internal IP First request resolves to external IP, second to internal
CNAME to internal Attacker domain CNAMEs to internal DNS points to internal hostname
URL parser confusion http://attacker.com#@internal Different parsing behaviors
Redirect chains External URL redirects to internal Follow redirects carefully
IPv6 scope ID http://[fe80::1%25eth0] Interface-scoped IPv6
Rare IP formats http://127.1 Shortened IP notation
DNS Rebinding Prevention
  1. Resolve DNS before making request
  2. Validate resolved IP is not internal
  3. Pin the resolved IP for the request (don't re-resolve)
  4. Or: Resolve twice with delay, ensure both resolve to same external IP
Cloud Metadata Protection

Block access to cloud metadata endpoints:

  • AWS: 169.254.169.254
  • GCP: metadata.google.internal, 169.254.169.254, http://metadata
  • Azure: 169.254.169.254
  • DigitalOcean: 169.254.169.254
Implementation Checklist
  • Validate URL scheme is HTTP/HTTPS only
  • Resolve DNS and validate IP is not private/internal
  • Block cloud metadata IPs explicitly
  • Limit or disable redirect following
  • If following redirects, validate each hop
  • Set timeout on requests
  • Limit response size
  • Use network isolation where possible

Insecure File Upload

File uploads must validate type, content, and size to prevent various attacks.

Validation Requirements

1. File Type Validation

  • Check file extension against allowlist
  • Validate magic bytes/file signature match expected type
  • Never rely on just one check

2. File Content Validation

  • Read and verify magic bytes
  • For images: attempt to process with image library (detects malformed files)
  • For documents: scan for macros, embedded objects
  • Check for polyglot files (files valid as multiple types)

3. File Size Limits

  • Set maximum file size server-side
  • Configure web server/proxy limits as well
  • Consider per-file-type limits (images smaller than videos)
Common Bypasses and Attacks
Attack Description Prevention
Extension bypass shell.php.jpg Check full extension, use allowlist
Null byte shell.php%00.jpg Sanitize filename, check for null bytes
Double extension shell.jpg.php Only allow single extension
MIME type spoofing Set Content-Type to image/jpeg Validate magic bytes
Magic byte injection Prepend valid magic bytes to malicious file Check entire file structure, not just header
Polyglot files File valid as both JPEG and JavaScript Parse file as expected type, reject if invalid
SVG with JavaScript <svg onload="alert(1)"> Sanitize SVG or disallow entirely
XXE via file upload Malicious DOCX, XLSX (which are XML) Disable external entities in parser
ZIP slip ../../../etc/passwd in archive Validate extracted paths
ImageMagick exploits Specially crafted images Keep ImageMagick updated, use policy.xml
Filename injection ; rm -rf / in filename Sanitize filenames, use random names
Content-type confusion Browser MIME sniffing Set X-Content-Type-Options: nosniff
Magic Bytes Reference
Type Magic Bytes (hex)
JPEG FF D8 FF
PNG 89 50 4E 47 0D 0A 1A 0A
GIF 47 49 46 38
PDF 25 50 44 46
ZIP 50 4B 03 04
DOCX/XLSX 50 4B 03 04 (ZIP-based)
Secure Upload Handling
  1. Rename files: Use random UUID names, discard original
  2. Store outside webroot: Or use separate domain for uploads
  3. Serve with correct headers:
    • Content-Disposition: attachment (forces download)
    • X-Content-Type-Options: nosniff
    • Content-Type matching actual file type
  4. Use CDN/separate domain: Isolate uploaded content from main app
  5. Set restrictive permissions: Uploaded files should not be executable

SQL Injection

SQL injection occurs when user input is incorporated into SQL queries without proper handling.

Prevention Methods

1. Parameterized Queries (Prepared Statements) — PRIMARY DEFENSE

-- VULNERABLE
query = "SELECT * FROM users WHERE id = " + userId

-- SECURE
query = "SELECT * FROM users WHERE id = ?"
execute(query, [userId])

2. ORM Usage

  • Use ORM methods that automatically parameterize
  • Be cautious with raw query methods in ORMs
  • Watch for ORM-specific injection points

3. Input Validation

  • Validate data types (integer should be integer)
  • Whitelist allowed values where applicable
  • This is defense-in-depth, not primary defense
Injection Points to Watch
  • WHERE clauses
  • ORDER BY clauses (often overlooked—can't use parameters, must whitelist)
  • LIMIT/OFFSET values
  • Table and column names (can't parameterize—must whitelist)
  • INSERT values
  • UPDATE SET values
  • IN clauses with dynamic lists
  • LIKE patterns (also escape wildcards: %, _)
Additional Defenses
  • Least privilege: Database user should have minimum required permissions
  • Disable dangerous functions: Like xp_cmdshell in SQL Server
  • Error handling: Never expose SQL errors to users

XML External Entity (XXE)

XXE vulnerabilities occur when XML parsers process external entity references in user-supplied XML.

Vulnerable Scenarios

Direct XML Input:

  • SOAP APIs
  • XML-RPC
  • XML file uploads
  • Configuration file parsing
  • RSS/Atom feed processing

Indirect XML:

  • JSON/other format converted to XML server-side
  • Office documents (DOCX, XLSX, PPTX are ZIP with XML)
  • SVG files (XML-based)
  • SAML assertions
  • PDF with XFA forms
Prevention by Language/Parser

Java:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setExpandEntityReferences(false);

Python (lxml):

from lxml import etree
parser = etree.XMLParser(resolve_entities=False, no_network=True)
# Or use defusedxml library

PHP:

libxml_disable_entity_loader(true);
// Or use XMLReader with proper settings

Node.js:

// Use libraries that disable DTD processing by default
// If using libxmljs, set { noent: false, dtdload: false }

.NET:

XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
settings.XmlResolver = null;
XXE Prevention Checklist
  • Disable DTD processing entirely if possible
  • Disable external entity resolution
  • Disable external DTD loading
  • Disable XInclude processing
  • Use latest patched XML parser versions
  • Validate/sanitize XML before parsing if DTD needed
  • Consider using JSON instead of XML where possible

Path Traversal

Path traversal vulnerabilities occur when user input controls file paths, allowing access to files outside intended directories.

Vulnerable Patterns
# VULNERABLE
file_path = "/uploads/" + user_input
file_path = base_dir + request.params['file']
template = "templates/" + user_provided_template
Prevention Strategies

1. Avoid User Input in Paths

# Instead of using user input directly
# Use indirect references
files = {'report': '/reports/q1.pdf', 'invoice': '/invoices/2024.pdf'}
file_path = files.get(user_input)  # Returns None if invalid

2. Canonicalization and Validation

import os

def safe_join(base_directory, user_path):
    # Ensure base is absolute and normalized
    base = os.path.abspath(os.path.realpath(base_directory))
    
    # Join and then resolve the result
    target = os.path.abspath(os.path.realpath(os.path.join(base, user_path)))
    
    # Ensure the commonpath is the base directory
    if os.path.commonpath([base, target]) != base:
        raise ValueError("Error!")
    
    return target

3. Input Sanitization

  • Remove or reject .. sequences
  • Remove or reject absolute path indicators (/, C:)
  • Whitelist allowed characters (alphanumeric, dash, underscore)
  • Validate file extension if applicable
Path Traversal Checklist
  • Never use user input directly in file paths
  • Canonicalize paths and validate against base directory
  • Restrict file extensions if applicable
  • Test with various encoding and bypass techniques

Security Headers Checklist

Include these headers in all responses:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Security-Policy: [see XSS section]
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Cache-Control: no-store (for sensitive pages)

JWT Security

JWT misconfigurations can lead to full authentication bypass and token forgery.

Vulnerabilities
Vulnerability Prevention
alg: none attack Always verify algorithm server-side, reject none
Algorithm confusion Explicitly specify expected algorithm, never derive from token
Weak HMAC secrets Use 256+ bit cryptographically random secrets
Missing expiration Always set exp claim
Token in localStorage Store in httpOnly, Secure, SameSite=Strict cookies, never localStorage
Secure Implementation
// 1. SIGNING
// Always use environment variables for secrets
const secret = process.env.JWT_SECRET; 

const token = jwt.sign({
  sub: userId,
  iat: Math.floor(Date.now() / 1000),
  exp: Math.floor(Date.now() / 1000) + (15 * 60), // 15 mins (Short-lived)
  jti: crypto.randomUUID() // Unique ID for revocation/blacklisting
}, secret, { 
  algorithm: 'HS256' 
});

// 2. SENDING (Cookie Best Practices)
// Protect against XSS and CSRF
res.cookie('token', token, {
  httpOnly: true, 
  secure: true,    
  sameSite: 'strict'
});

// 3. VERIFYING
// CRITICAL: Whitelist the allowed algorithm
jwt.verify(token, secret, { algorithms: ['HS256'] }, (err, decoded) => {
  if (err) {
    // Handle invalid token
  }
  // Trust the payload
});
JWT Checklist
  • Algorithm explicitly specified on verification (never trust token header)
  • alg: none rejected
  • Secret is 256+ bits of random data (not a password or phrase)
  • exp claim always set and validated
  • Tokens stored in httpOnly cookies (not localStorage/sessionStorage)
  • Refresh token rotation implemented (old refresh token invalidated on use)

API Security

Mass Assignment

Accepting unfiltered request bodies can lead to privilege escalation.

// VULNERABLE — user can set { role: "admin" } in request body
User.update(req.body)

// SECURE — whitelist allowed fields
const allowed = ['name', 'email', 'avatar']
const updates = pick(req.body, allowed)
User.update(updates)

This applies to any ORM/framework — always explicitly define which fields a request can modify.

GraphQL
Vulnerability Prevention
Introspection in production Disable introspection in production environments.
Query depth attack Implement query depth limiting (e.g., maximum of 10 levels).
Query complexity attack Calculate and enforce strict query cost limits.
Batching attack Limit the number of operations allowed per single request.
const server = new ApolloServer({
  introspection: process.env.NODE_ENV !== 'production',
  validationRules: [
    depthLimit(10),
    costAnalysis({ maximumCost: 1000 })
  ]
})

General Security Principles

When generating code, always:

  1. Validate all input server-side — Never trust client-side validation alone
  2. Use parameterized queries — Never concatenate user input into queries
  3. Encode output contextually — HTML, JS, URL, CSS contexts need different encoding
  4. Apply authentication checks — On every endpoint, not just at routing
  5. Apply authorization checks — Verify the user can access the specific resource
  6. Use secure defaults
  7. Handle errors securely — Don't leak stack traces or internal details to users
  8. Keep dependencies updated — Use tools to track vulnerable dependencies

When unsure, choose the more restrictive/secure option and document the security consideration in comments.

1---
2name: VibeSec-Skill
3description: This skill helps Claude write secure web applications. Use this when working on any web application or when a user requests a scan or audit to ensure security best practices are followed.
4---
5 
6# Secure Coding Guide for Web Applications
7 
8## Overview
9 
10This guide provides comprehensive secure coding practices for web applications. As an AI assistant, your role is to approach code from a **bug hunter's perspective** and make applications **as secure as possible** without breaking functionality.
11 
12**Key Principles:**
13- Defense in depth: Never rely on a single security control
14- Fail securely: When something fails, fail closed (deny access)
15- Least privilege: Grant minimum permissions necessary
16- Input validation: Never trust user input, validate everything server-side
17- Output encoding: Encode data appropriately for the context it's rendered in
18 
19---
20 
21## Access Control Issues
22 
23Access control vulnerabilities occur when users can access resources or perform actions beyond their intended permissions.
24 
25### Core Requirements
26 
27For **every data point and action** that requires authentication:
28 
291. **User-Level Authorization**
30 - Each user must only access/modify their own data
31 - No user should access data from other users or organizations
32 - Always verify ownership at the data layer, not just the route level
33 
342. **Use UUIDs Instead of Sequential IDs**
35 - Use UUIDv4 or similar non-guessable identifiers
36 - Exception: Only use sequential IDs if explicitly requested by user
37 
383. **Account Lifecycle Handling**
39 - When a user is removed from an organization: immediately revoke all access tokens and sessions
40 - When an account is deleted/deactivated: invalidate all active sessions and API keys
41 - Implement token revocation lists or short-lived tokens with refresh mechanisms
42 
43### Authorization Checks Checklist
44 
45- [ ] Verify user owns the resource on every request (don't trust client-side data)
46- [ ] Check organization membership for multi-tenant apps
47- [ ] Validate role permissions for role-based actions
48- [ ] Re-validate permissions after any privilege change
49- [ ] Check parent resource ownership (e.g., if accessing a comment, verify user owns the parent post)
50 
51### Common Pitfalls to Avoid
52 
53- **IDOR (Insecure Direct Object Reference)**: Always verify the requesting user has permission to access the requested resource ID
54- **Privilege Escalation**: Validate role changes server-side; never trust role info from client
55- **Horizontal Access**: User A accessing User B's resources with the same privilege level
56- **Vertical Access**: Regular user accessing admin functionality
57- **Mass Assignment**: Filter which fields users can update; don't blindly accept all request body fields
58 
59### Implementation Pattern
60 
61```
62# Pseudocode for secure resource access
63function getResource(resourceId, currentUser):
64 resource = database.find(resourceId)
65 
66 if resource is null:
67 return 404 # Don't reveal if resource exists
68 
69 if resource.ownerId != currentUser.id:
70 if not currentUser.hasOrgAccess(resource.orgId):
71 return 404 # Return 404, not 403, to prevent enumeration
72 
73 return resource
74```
75 
76---
77 
78## Client-Side Bugs
79 
80### Cross-Site Scripting (XSS)
81 
82Every input controllable by the user—whether directly or indirectly—must be sanitized against XSS.
83 
84#### Input Sources to Protect
85 
86**Direct Inputs:**
87- Form fields (email, name, bio, comments, etc.)
88- Search queries
89- File names during upload
90- Rich text editors / WYSIWYG content
91 
92**Indirect Inputs:**
93- URL parameters and query strings
94- URL fragments (hash values)
95- HTTP headers used in the application (Referer, User-Agent if displayed)
96- Data from third-party APIs displayed to users
97- WebSocket messages
98- postMessage data from iframes
99- LocalStorage/SessionStorage values if rendered
100 
101**Often Overlooked:**
102- Error messages that reflect user input
103- PDF/document generators that accept HTML
104- Email templates with user data
105- Log viewers in admin panels
106- JSON responses rendered as HTML
107- SVG file uploads (can contain JavaScript)
108- Markdown rendering (if allowing HTML)
109 
110#### Protection Strategies
111 
1121. **Output Encoding** (Context-Specific)
113 - HTML context: HTML entity encode (`<` → `&lt;`)
114 - JavaScript context: JavaScript escape
115 - URL context: URL encode
116 - CSS context: CSS escape
117 - Use framework's built-in escaping (React's JSX, Vue's {{ }}, etc.)
118 
1192. **Content Security Policy (CSP)**
120 ```
121 Content-Security-Policy:
122 default-src 'self';
123 script-src 'self';
124 style-src 'self' 'unsafe-inline';
125 img-src 'self' data: https:;
126 font-src 'self';
127 connect-src 'self' https://api.yourdomain.com;
128 frame-ancestors 'none';
129 base-uri 'self';
130 form-action 'self';
131 ```
132 - Avoid `'unsafe-inline'` and `'unsafe-eval'` for scripts
133 - Use nonces or hashes for inline scripts when necessary
134 - Report violations: `report-uri /csp-report`
135 
1363. **Input Sanitization**
137 - Use established libraries (DOMPurify for HTML)
138 - Whitelist allowed tags/attributes for rich text
139 - Strip or encode dangerous patterns
140 
1414. **Additional Headers**
142 - `X-Content-Type-Options: nosniff`
143 - `X-Frame-Options: DENY` (or use CSP frame-ancestors)
144 
145---
146 
147### Cross-Site Request Forgery (CSRF)
148 
149Every state-changing endpoint must be protected against CSRF attacks.
150 
151#### Endpoints Requiring CSRF Protection
152 
153**Authenticated Actions:**
154- All POST, PUT, PATCH, DELETE requests
155- Any GET request that changes state (fix these to use proper HTTP methods)
156- File uploads
157- Settings changes
158- Payment/transaction endpoints
159 
160**Pre-Authentication Actions:**
161- Login endpoints (prevent login CSRF)
162- Signup endpoints
163- Password reset request endpoints
164- Password change endpoints
165- Email/phone verification endpoints
166- OAuth callback endpoints
167 
168#### Protection Mechanisms
169 
1701. **CSRF Tokens**
171 - Generate cryptographically random tokens
172 - Tie token to user session
173 - Validate on every state-changing request
174 - Regenerate after login (prevent session fixation combo)
175 
1762. **SameSite Cookies**
177 ```
178 Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
179 ```
180 - `Strict`: Cookie never sent cross-site (best security)
181 - `Lax`: Cookie sent on top-level navigations (good balance)
182 - Always combine with CSRF tokens for defense in depth
183 
1843. **Double Submit Cookie Pattern**
185 - Send CSRF token in both cookie and request body/header
186 - Server validates they match
187 
188#### Edge Cases and Common Mistakes
189 
190- **Token presence check**: CSRF validation must NOT depend on whether the token is present, always require it
191- **Token per form**: Consider unique tokens per form for sensitive operations
192- **JSON APIs**: Don't assume JSON content-type prevents CSRF; validate Origin/Referer headers AND use tokens
193- **CORS misconfiguration**: Overly permissive CORS can bypass SameSite cookies
194- **Subdomains**: CSRF tokens should be scoped because subdomain takeover can lead to CSRF
195- **Flash/PDF uploads**: Legacy browser plugins could bypass SameSite
196- **GET requests with side effects**: Never perform state changes on GET
197- **Token leakage**: Don't include CSRF tokens in URLs
198- **Token in URL vs Header**: Prefer custom headers (X-CSRF-Token) over URL parameters
199 
200 
201#### Verification Checklist
202 
203- [ ] Token is cryptographically random (use secure random generator)
204- [ ] Token is tied to user session
205- [ ] Token is validated server-side on all state-changing requests
206- [ ] Missing token = rejected request
207- [ ] Token regenerated on authentication state change
208- [ ] SameSite cookie attribute is set
209- [ ] Secure and HttpOnly flags on session cookies
210 
211---
212 
213### Secret Keys and Sensitive Data Exposure
214 
215No secrets or sensitive information should be accessible to client-side code.
216 
217#### Never Expose in Client-Side Code
218 
219**API Keys and Secrets:**
220- Third-party API keys (Stripe, AWS, etc.)
221- Database connection strings
222- JWT signing secrets
223- Encryption keys
224- OAuth client secrets
225- Internal service URLs/credentials
226 
227**Sensitive User Data:**
228- Full credit card numbers
229- Social Security Numbers
230- Passwords (even hashed)
231- Security questions/answers
232- Full phone numbers (mask them: ***-***-1234)
233- Sensitive PII that isn't needed for display
234 
235**Infrastructure Details:**
236- Internal IP addresses
237- Database schemas
238- Debug information
239- Stack traces in production
240- Server software versions
241 
242#### Where Secrets Hide (Check These!)
243 
244- JavaScript bundles (including source maps)
245- HTML comments
246- Hidden form fields
247- Data attributes
248- LocalStorage/SessionStorage
249- Initial state/hydration data in SSR apps
250- Environment variables exposed via build tools (NEXT_PUBLIC_*, REACT_APP_*)
251 
252#### Best Practices
253 
2541. **Environment Variables**: Store secrets in `.env` files
2552. **Server-Side Only**: Make API calls requiring secrets from backend only
256 
257---
258 
259## Open Redirect
260 
261Any endpoint accepting a URL for redirection must be protected against open redirect attacks.
262 
263### Protection Strategies
264 
2651. **Allowlist Validation**
266 ```
267 allowed_domains = ['yourdomain.com', 'app.yourdomain.com']
268 
269 function isValidRedirect(url):
270 parsed = parseUrl(url)
271 return parsed.hostname in allowed_domains
272 ```
273 
2742. **Relative URLs Only**
275 - Only accept paths (e.g., `/dashboard`) not full URLs
276 - Validate the path starts with `/` and doesn't contain `//`
277 
2783. **Indirect References**
279 - Use a mapping instead of raw URLs: `?redirect=dashboard` → lookup to `/dashboard`
280 
281### Bypass Techniques to Block
282 
283| Technique | Example | Why It Works |
284|-----------|---------|--------------|
285| @ symbol | `https://[email protected]` | Browser navigates to evil.com with legit.com as username |
286| Subdomain abuse | `https://legit.com.evil.com` | evil.com owns the subdomain |
287| Protocol tricks | `javascript:alert(1)` | XSS via redirect |
288| Double URL encoding | `%252f%252fevil.com` | Decodes to `//evil.com` after double decode |
289| Backslash | `https://legit.com\@evil.com` | Some parsers normalize `\` to `/` |
290| Null byte | `https://legit.com%00.evil.com` | Some parsers truncate at null |
291| Tab/newline | `https://legit.com%09.evil.com` | Whitespace confusion |
292| Unicode normalization | `https://legіt.com` (Cyrillic і) | IDN homograph attack |
293| Data URLs | `data:text/html,<script>...` | Direct payload execution |
294| Protocol-relative | `//evil.com` | Uses current page's protocol |
295| Fragment abuse | `https://legit.com#@evil.com` | Parsed differently by different libraries |
296 
297### IDN Homograph Attack Protection
298 
299- Convert URLs to Punycode before validation
300- Consider blocking non-ASCII domains entirely for sensitive redirects
301 
302 
303---
304 
305### Password Security
306 
307#### Password Requirements
308 
309- Minimum 8 characters (12+ recommended)
310- No maximum length (or very high, e.g., 128 chars)
311- Allow all characters including special chars
312- Don't require specific character types (let users choose strong passwords)
313 
314#### Storage
315 
316- Use Argon2id, bcrypt, or scrypt
317- Never MD5, SHA1, or plain SHA256
318 
319---
320 
321## Server-Side Bugs
322 
323### Server-Side Request Forgery (SSRF)
324 
325Any functionality where the server makes requests to URLs provided or influenced by users must be protected.
326 
327#### Potential Vulnerable Features
328 
329- Webhooks (user provides callback URL)
330- URL previews
331- PDF generators from URLs
332- Image/file fetching from URLs
333- Import from URL features
334- RSS/feed readers
335- API integrations with user-provided endpoints
336- Proxy functionality
337- HTML to PDF/image converters
338 
339#### Protection Strategies
340 
3411. **Allowlist Approach** (Preferred)
342 - Only allow requests to pre-approved domains
343 - Maintain a strict allowlist for integrations
344 
3452. **Network Segmentation**
346 - Run URL-fetching services in isolated network
347 - Block access to internal network, cloud metadata
348 
349#### IP and DNS Bypass Techniques to Block
350 
351| Technique | Example | Description |
352|-----------|---------|-------------|
353| Decimal IP | `http://2130706433` | 127.0.0.1 as decimal |
354| Octal IP | `http://0177.0.0.1` | Octal representation |
355| Hex IP | `http://0x7f.0x0.0x0.0x1` | Hexadecimal |
356| IPv6 localhost | `http://[::1]` | IPv6 loopback |
357| IPv6 mapped IPv4 | `http://[::ffff:127.0.0.1]` | IPv4-mapped IPv6 |
358| Short IPv6 | `http://[::]` | All zeros |
359| DNS rebinding | Attacker's DNS returns internal IP | First request resolves to external IP, second to internal |
360| CNAME to internal | Attacker domain CNAMEs to internal | DNS points to internal hostname |
361| URL parser confusion | `http://attacker.com#@internal` | Different parsing behaviors |
362| Redirect chains | External URL redirects to internal | Follow redirects carefully |
363| IPv6 scope ID | `http://[fe80::1%25eth0]` | Interface-scoped IPv6 |
364| Rare IP formats | `http://127.1` | Shortened IP notation |
365 
366#### DNS Rebinding Prevention
367 
3681. Resolve DNS before making request
3692. Validate resolved IP is not internal
3703. Pin the resolved IP for the request (don't re-resolve)
3714. Or: Resolve twice with delay, ensure both resolve to same external IP
372 
373#### Cloud Metadata Protection
374 
375Block access to cloud metadata endpoints:
376- AWS: `169.254.169.254`
377- GCP: `metadata.google.internal`, `169.254.169.254`, `http://metadata`
378- Azure: `169.254.169.254`
379- DigitalOcean: `169.254.169.254`
380 
381#### Implementation Checklist
382 
383- [ ] Validate URL scheme is HTTP/HTTPS only
384- [ ] Resolve DNS and validate IP is not private/internal
385- [ ] Block cloud metadata IPs explicitly
386- [ ] Limit or disable redirect following
387- [ ] If following redirects, validate each hop
388- [ ] Set timeout on requests
389- [ ] Limit response size
390- [ ] Use network isolation where possible
391 
392---
393 
394### Insecure File Upload
395 
396File uploads must validate type, content, and size to prevent various attacks.
397 
398#### Validation Requirements
399 
400**1. File Type Validation**
401- Check file extension against allowlist
402- Validate magic bytes/file signature match expected type
403- Never rely on just one check
404 
405**2. File Content Validation**
406- Read and verify magic bytes
407- For images: attempt to process with image library (detects malformed files)
408- For documents: scan for macros, embedded objects
409- Check for polyglot files (files valid as multiple types)
410 
411**3. File Size Limits**
412- Set maximum file size server-side
413- Configure web server/proxy limits as well
414- Consider per-file-type limits (images smaller than videos)
415 
416#### Common Bypasses and Attacks
417 
418| Attack | Description | Prevention |
419|--------|-------------|------------|
420| Extension bypass | `shell.php.jpg` | Check full extension, use allowlist |
421| Null byte | `shell.php%00.jpg` | Sanitize filename, check for null bytes |
422| Double extension | `shell.jpg.php` | Only allow single extension |
423| MIME type spoofing | Set Content-Type to image/jpeg | Validate magic bytes |
424| Magic byte injection | Prepend valid magic bytes to malicious file | Check entire file structure, not just header |
425| Polyglot files | File valid as both JPEG and JavaScript | Parse file as expected type, reject if invalid |
426| SVG with JavaScript | `<svg onload="alert(1)">` | Sanitize SVG or disallow entirely |
427| XXE via file upload | Malicious DOCX, XLSX (which are XML) | Disable external entities in parser |
428| ZIP slip | `../../../etc/passwd` in archive | Validate extracted paths |
429| ImageMagick exploits | Specially crafted images | Keep ImageMagick updated, use policy.xml |
430| Filename injection | `; rm -rf /` in filename | Sanitize filenames, use random names |
431| Content-type confusion | Browser MIME sniffing | Set `X-Content-Type-Options: nosniff` |
432 
433#### Magic Bytes Reference
434 
435| Type | Magic Bytes (hex) |
436|------|-------------------|
437| JPEG | `FF D8 FF` |
438| PNG | `89 50 4E 47 0D 0A 1A 0A` |
439| GIF | `47 49 46 38` |
440| PDF | `25 50 44 46` |
441| ZIP | `50 4B 03 04` |
442| DOCX/XLSX | `50 4B 03 04` (ZIP-based) |
443 
444#### Secure Upload Handling
445 
4461. **Rename files**: Use random UUID names, discard original
4472. **Store outside webroot**: Or use separate domain for uploads
4483. **Serve with correct headers**:
449 - `Content-Disposition: attachment` (forces download)
450 - `X-Content-Type-Options: nosniff`
451 - `Content-Type` matching actual file type
4524. **Use CDN/separate domain**: Isolate uploaded content from main app
4535. **Set restrictive permissions**: Uploaded files should not be executable
454 
455---
456 
457### SQL Injection
458 
459SQL injection occurs when user input is incorporated into SQL queries without proper handling.
460 
461#### Prevention Methods
462 
463**1. Parameterized Queries (Prepared Statements)** — PRIMARY DEFENSE
464```sql
465-- VULNERABLE
466query = "SELECT * FROM users WHERE id = " + userId
467 
468-- SECURE
469query = "SELECT * FROM users WHERE id = ?"
470execute(query, [userId])
471```
472 
473**2. ORM Usage**
474- Use ORM methods that automatically parameterize
475- Be cautious with raw query methods in ORMs
476- Watch for ORM-specific injection points
477 
478**3. Input Validation**
479- Validate data types (integer should be integer)
480- Whitelist allowed values where applicable
481- This is defense-in-depth, not primary defense
482 
483#### Injection Points to Watch
484 
485- WHERE clauses
486- ORDER BY clauses (often overlooked—can't use parameters, must whitelist)
487- LIMIT/OFFSET values
488- Table and column names (can't parameterize—must whitelist)
489- INSERT values
490- UPDATE SET values
491- IN clauses with dynamic lists
492- LIKE patterns (also escape wildcards: %, _)
493 
494#### Additional Defenses
495 
496- **Least privilege**: Database user should have minimum required permissions
497- **Disable dangerous functions**: Like `xp_cmdshell` in SQL Server
498- **Error handling**: Never expose SQL errors to users
499 
500---
501 
502### XML External Entity (XXE)
503 
504XXE vulnerabilities occur when XML parsers process external entity references in user-supplied XML.
505 
506#### Vulnerable Scenarios
507 
508**Direct XML Input:**
509- SOAP APIs
510- XML-RPC
511- XML file uploads
512- Configuration file parsing
513- RSS/Atom feed processing
514 
515**Indirect XML:**
516- JSON/other format converted to XML server-side
517- Office documents (DOCX, XLSX, PPTX are ZIP with XML)
518- SVG files (XML-based)
519- SAML assertions
520- PDF with XFA forms
521 
522 
523#### Prevention by Language/Parser
524 
525**Java:**
526```java
527DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
528dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
529dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
530dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
531dbf.setExpandEntityReferences(false);
532```
533 
534**Python (lxml):**
535```python
536from lxml import etree
537parser = etree.XMLParser(resolve_entities=False, no_network=True)
538# Or use defusedxml library
539```
540 
541**PHP:**
542```php
543libxml_disable_entity_loader(true);
544// Or use XMLReader with proper settings
545```
546 
547**Node.js:**
548```javascript
549// Use libraries that disable DTD processing by default
550// If using libxmljs, set { noent: false, dtdload: false }
551```
552 
553**.NET:**
554```csharp
555XmlReaderSettings settings = new XmlReaderSettings();
556settings.DtdProcessing = DtdProcessing.Prohibit;
557settings.XmlResolver = null;
558```
559 
560#### XXE Prevention Checklist
561 
562- [ ] Disable DTD processing entirely if possible
563- [ ] Disable external entity resolution
564- [ ] Disable external DTD loading
565- [ ] Disable XInclude processing
566- [ ] Use latest patched XML parser versions
567- [ ] Validate/sanitize XML before parsing if DTD needed
568- [ ] Consider using JSON instead of XML where possible
569 
570---
571 
572### Path Traversal
573 
574Path traversal vulnerabilities occur when user input controls file paths, allowing access to files outside intended directories.
575 
576#### Vulnerable Patterns
577 
578```python
579# VULNERABLE
580file_path = "/uploads/" + user_input
581file_path = base_dir + request.params['file']
582template = "templates/" + user_provided_template
583```
584 
585#### Prevention Strategies
586 
587**1. Avoid User Input in Paths**
588```python
589# Instead of using user input directly
590# Use indirect references
591files = {'report': '/reports/q1.pdf', 'invoice': '/invoices/2024.pdf'}
592file_path = files.get(user_input) # Returns None if invalid
593```
594 
595**2. Canonicalization and Validation**
596 
597```python
598import os
599 
600def safe_join(base_directory, user_path):
601 # Ensure base is absolute and normalized
602 base = os.path.abspath(os.path.realpath(base_directory))
603 
604 # Join and then resolve the result
605 target = os.path.abspath(os.path.realpath(os.path.join(base, user_path)))
606 
607 # Ensure the commonpath is the base directory
608 if os.path.commonpath([base, target]) != base:
609 raise ValueError("Error!")
610 
611 return target
612```
613 
614**3. Input Sanitization**
615- Remove or reject `..` sequences
616- Remove or reject absolute path indicators (`/`, `C:`)
617- Whitelist allowed characters (alphanumeric, dash, underscore)
618- Validate file extension if applicable
619 
620 
621#### Path Traversal Checklist
622 
623- [ ] Never use user input directly in file paths
624- [ ] Canonicalize paths and validate against base directory
625- [ ] Restrict file extensions if applicable
626- [ ] Test with various encoding and bypass techniques
627 
628---
629 
630## Security Headers Checklist
631 
632Include these headers in all responses:
633 
634```
635Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
636Content-Security-Policy: [see XSS section]
637X-Content-Type-Options: nosniff
638X-Frame-Options: DENY
639Referrer-Policy: strict-origin-when-cross-origin
640Cache-Control: no-store (for sensitive pages)
641```
642 
643---
644 
645## JWT Security
646 
647JWT misconfigurations can lead to full authentication bypass and token forgery.
648 
649### Vulnerabilities
650 
651| Vulnerability | Prevention |
652|---------------|------------|
653| `alg: none` attack | Always verify algorithm server-side, reject `none` |
654| Algorithm confusion | Explicitly specify expected algorithm, never derive from token |
655| Weak HMAC secrets | Use 256+ bit cryptographically random secrets |
656| Missing expiration | Always set `exp` claim |
657| Token in localStorage | Store in httpOnly, Secure, SameSite=Strict cookies, never localStorage |
658 
659 
660### Secure Implementation
661 
662```javascript
663// 1. SIGNING
664// Always use environment variables for secrets
665const secret = process.env.JWT_SECRET;
666 
667const token = jwt.sign({
668 sub: userId,
669 iat: Math.floor(Date.now() / 1000),
670 exp: Math.floor(Date.now() / 1000) + (15 * 60), // 15 mins (Short-lived)
671 jti: crypto.randomUUID() // Unique ID for revocation/blacklisting
672}, secret, {
673 algorithm: 'HS256'
674});
675 
676// 2. SENDING (Cookie Best Practices)
677// Protect against XSS and CSRF
678res.cookie('token', token, {
679 httpOnly: true,
680 secure: true,
681 sameSite: 'strict'
682});
683 
684// 3. VERIFYING
685// CRITICAL: Whitelist the allowed algorithm
686jwt.verify(token, secret, { algorithms: ['HS256'] }, (err, decoded) => {
687 if (err) {
688 // Handle invalid token
689 }
690 // Trust the payload
691});
692```
693 
694### JWT Checklist
695 
696- [ ] Algorithm explicitly specified on verification (never trust token header)
697- [ ] `alg: none` rejected
698- [ ] Secret is 256+ bits of random data (not a password or phrase)
699- [ ] `exp` claim always set and validated
700- [ ] Tokens stored in httpOnly cookies (not localStorage/sessionStorage)
701- [ ] Refresh token rotation implemented (old refresh token invalidated on use)
702 
703---
704 
705## API Security
706 
707### Mass Assignment
708 
709Accepting unfiltered request bodies can lead to privilege escalation.
710 
711```javascript
712// VULNERABLE — user can set { role: "admin" } in request body
713User.update(req.body)
714 
715// SECURE — whitelist allowed fields
716const allowed = ['name', 'email', 'avatar']
717const updates = pick(req.body, allowed)
718User.update(updates)
719```
720 
721This applies to any ORM/framework — always explicitly define which fields a request can modify.
722 
723### GraphQL
724 
725| Vulnerability | Prevention |
726| :--- | :--- |
727| Introspection in production | Disable introspection in production environments. |
728| Query depth attack | Implement query depth limiting (e.g., maximum of 10 levels). |
729| Query complexity attack | Calculate and enforce strict query cost limits. |
730| Batching attack | Limit the number of operations allowed per single request. |
731 
732 
733```javascript
734const server = new ApolloServer({
735 introspection: process.env.NODE_ENV !== 'production',
736 validationRules: [
737 depthLimit(10),
738 costAnalysis({ maximumCost: 1000 })
739 ]
740})
741```
742 
743---
744 
745## General Security Principles
746 
747When generating code, always:
748 
7491. **Validate all input server-side** — Never trust client-side validation alone
7502. **Use parameterized queries** — Never concatenate user input into queries
7513. **Encode output contextually** — HTML, JS, URL, CSS contexts need different encoding
7524. **Apply authentication checks** — On every endpoint, not just at routing
7535. **Apply authorization checks** — Verify the user can access the specific resource
7546. **Use secure defaults**
7557. **Handle errors securely** — Don't leak stack traces or internal details to users
7568. **Keep dependencies updated** — Use tools to track vulnerable dependencies
757 
758When unsure, choose the more restrictive/secure option and document the security consideration in comments.
759 

Discussion

Alternatives