compound-agent 1.7.6 → 2.0.0
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/CHANGELOG.md +45 -1
- package/README.md +70 -47
- package/bin/ca +32 -0
- package/package.json +19 -78
- package/scripts/postinstall.cjs +221 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -13158
- package/dist/cli.js.map +0 -1
- package/dist/index.d.ts +0 -3730
- package/dist/index.js +0 -3240
- package/dist/index.js.map +0 -1
- package/docs/research/AgenticAiCodebaseGuide.md +0 -1206
- package/docs/research/BuildingACCompilerAnthropic.md +0 -116
- package/docs/research/HarnessEngineeringOpenAi.md +0 -220
- package/docs/research/code-review/systematic-review-methodology.md +0 -409
- package/docs/research/index.md +0 -76
- package/docs/research/learning-systems/knowledge-compounding-for-agents.md +0 -695
- package/docs/research/property-testing/property-based-testing-and-invariants.md +0 -742
- package/docs/research/scenario-testing/advanced-and-emerging.md +0 -470
- package/docs/research/scenario-testing/core-foundations.md +0 -507
- package/docs/research/scenario-testing/domain-specific-and-human-factors.md +0 -474
- package/docs/research/security/auth-patterns.md +0 -138
- package/docs/research/security/data-exposure.md +0 -185
- package/docs/research/security/dependency-security.md +0 -91
- package/docs/research/security/injection-patterns.md +0 -249
- package/docs/research/security/overview.md +0 -81
- package/docs/research/security/secrets-checklist.md +0 -92
- package/docs/research/security/secure-coding-failure.md +0 -297
- package/docs/research/software_architecture/01-science-of-decomposition.md +0 -615
- package/docs/research/software_architecture/02-architecture-under-uncertainty.md +0 -649
- package/docs/research/software_architecture/03-emergent-behavior-in-composed-systems.md +0 -644
- package/docs/research/spec_design/decision_theory_specifications_and_multi_criteria_tradeoffs.md +0 -0
- package/docs/research/spec_design/design_by_contract.md +0 -251
- package/docs/research/spec_design/domain_driven_design_strategic_modeling.md +0 -183
- package/docs/research/spec_design/formal_specification_methods.md +0 -161
- package/docs/research/spec_design/logic_and_proof_theory_under_the_curry_howard_correspondence.md +0 -250
- package/docs/research/spec_design/natural_language_formal_semantics_abuguity_in_specifications.md +0 -259
- package/docs/research/spec_design/requirements_engineering.md +0 -234
- package/docs/research/spec_design/systems_engineering_specifications_emergent_behavior_interface_contracts.md +0 -149
- package/docs/research/spec_design/what_is_this_about.md +0 -305
- package/docs/research/tdd/test-driven-development-methodology.md +0 -547
- package/docs/research/test-optimization-strategies.md +0 -401
- package/scripts/postinstall.mjs +0 -102
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
# Data Exposure Patterns
|
|
2
|
-
|
|
3
|
-
*February 23, 2026*
|
|
4
|
-
|
|
5
|
-
Reference for AI agents reviewing code for sensitive data leakage.
|
|
6
|
-
Derived from [secure-coding-failure.md](secure-coding-failure.md) section 4.8.
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## PII in Logs
|
|
11
|
-
|
|
12
|
-
Logging calls that dump unfiltered request data or user records.
|
|
13
|
-
|
|
14
|
-
### Unsafe patterns
|
|
15
|
-
|
|
16
|
-
```typescript
|
|
17
|
-
// Logging entire request body (may contain passwords, tokens, PII)
|
|
18
|
-
console.log('Request:', req.body);
|
|
19
|
-
logger.info('User login', { body: req.body });
|
|
20
|
-
|
|
21
|
-
// Logging user records with sensitive fields
|
|
22
|
-
logger.info('User fetched', user); // user object may include password_hash
|
|
23
|
-
|
|
24
|
-
// Logging authorization headers
|
|
25
|
-
console.log('Headers:', req.headers); // includes Authorization: Bearer ...
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
```python
|
|
29
|
-
# Logging full request object
|
|
30
|
-
logging.info("Request: %s", request.json)
|
|
31
|
-
|
|
32
|
-
# Logging user record
|
|
33
|
-
logger.info("User: %s", user.__dict__)
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### Safe patterns
|
|
37
|
-
|
|
38
|
-
```typescript
|
|
39
|
-
// Log only what you need
|
|
40
|
-
logger.info('User login', { userId: req.body.userId });
|
|
41
|
-
|
|
42
|
-
// Explicitly exclude sensitive fields
|
|
43
|
-
const { password, ...safeBody } = req.body;
|
|
44
|
-
logger.info('Request:', safeBody);
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
```python
|
|
48
|
-
# Log specific fields only
|
|
49
|
-
logger.info("User login: user_id=%s", request.json.get("user_id"))
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
## Verbose Error Responses
|
|
55
|
-
|
|
56
|
-
Stack traces and internal details sent to clients.
|
|
57
|
-
|
|
58
|
-
### Unsafe patterns
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
// Stack trace sent to client
|
|
62
|
-
app.use((err, req, res, next) => {
|
|
63
|
-
res.status(500).json({ error: err.message, stack: err.stack });
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// DB connection string in error
|
|
67
|
-
catch (err) {
|
|
68
|
-
res.status(500).json({ error: `DB error: ${err.message}` });
|
|
69
|
-
// err.message may contain: "connection to postgres://user:pass@host:5432 failed"
|
|
70
|
-
}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
```python
|
|
74
|
-
# Django DEBUG=True in production exposes full stack traces and settings
|
|
75
|
-
# Flask returning exception details
|
|
76
|
-
@app.errorhandler(500)
|
|
77
|
-
def handle_error(e):
|
|
78
|
-
return {"error": str(e), "trace": traceback.format_exc()}, 500
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Safe patterns
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
// Generic error to client, detailed error to logs
|
|
85
|
-
app.use((err, req, res, next) => {
|
|
86
|
-
logger.error('Internal error', { error: err.message, stack: err.stack });
|
|
87
|
-
res.status(500).json({ error: 'Internal server error' });
|
|
88
|
-
});
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
```python
|
|
92
|
-
@app.errorhandler(500)
|
|
93
|
-
def handle_error(e):
|
|
94
|
-
app.logger.error("Internal error: %s", e)
|
|
95
|
-
return {"error": "Internal server error"}, 500
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
---
|
|
99
|
-
|
|
100
|
-
## Sensitive Data in URLs
|
|
101
|
-
|
|
102
|
-
Tokens and PII in query parameters leak through referrer headers, browser history,
|
|
103
|
-
server logs, and proxy logs -- even with TLS.
|
|
104
|
-
|
|
105
|
-
### Unsafe patterns
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
// Token in query string
|
|
109
|
-
app.get('/api/verify?token=abc123', verifyEmail);
|
|
110
|
-
// Leaks in: server access logs, browser history, Referer header
|
|
111
|
-
|
|
112
|
-
// PII in URL
|
|
113
|
-
app.get('/api/users?email=user@example.com', findUser);
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### Safe patterns
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
// Token in request body or header
|
|
120
|
-
app.post('/api/verify', verifyEmail); // token in POST body
|
|
121
|
-
|
|
122
|
-
// Use path params for non-sensitive IDs only; sensitive data in body/headers
|
|
123
|
-
app.get('/api/users/:id', findUser); // opaque ID, not email
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
---
|
|
127
|
-
|
|
128
|
-
## Overly Broad API Responses
|
|
129
|
-
|
|
130
|
-
Returning full database records instead of selecting specific fields.
|
|
131
|
-
|
|
132
|
-
### Unsafe patterns
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
// Returns entire user record including internal fields
|
|
136
|
-
app.get('/api/users/:id', async (req, res) => {
|
|
137
|
-
const user = await db.get('SELECT * FROM users WHERE id = ?', [req.params.id]);
|
|
138
|
-
res.json(user);
|
|
139
|
-
// Response includes: password_hash, internal_id, created_by_admin, etc.
|
|
140
|
-
});
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
```python
|
|
144
|
-
# Django serializer with all fields
|
|
145
|
-
class UserSerializer(serializers.ModelSerializer):
|
|
146
|
-
class Meta:
|
|
147
|
-
model = User
|
|
148
|
-
fields = '__all__' # includes password_hash, is_superuser, etc.
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### Safe patterns
|
|
152
|
-
|
|
153
|
-
```typescript
|
|
154
|
-
// Select only needed fields
|
|
155
|
-
const user = await db.get(
|
|
156
|
-
'SELECT id, name, email FROM users WHERE id = ?',
|
|
157
|
-
[req.params.id]
|
|
158
|
-
);
|
|
159
|
-
res.json(user);
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
```python
|
|
163
|
-
class UserSerializer(serializers.ModelSerializer):
|
|
164
|
-
class Meta:
|
|
165
|
-
model = User
|
|
166
|
-
fields = ['id', 'name', 'email']
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
---
|
|
170
|
-
|
|
171
|
-
## Detection Heuristics
|
|
172
|
-
|
|
173
|
-
| Pattern to match | What it indicates | Severity |
|
|
174
|
-
|-----------------|-------------------|----------|
|
|
175
|
-
| `console.log(req.body)`, `console.log(req.headers)` | PII/credentials in logs | P2 |
|
|
176
|
-
| `logger.info(user)`, `logger.info(request.json)` | Unfiltered record in logs | P2 |
|
|
177
|
-
| Error handler returning `err.stack` or `err.message` to response | Internal details exposed to client | P2 |
|
|
178
|
-
| `DEBUG = True` in production config | Full stack traces and settings exposed | P1 |
|
|
179
|
-
| Query params named `token`, `key`, `auth`, `password`, `secret` | Sensitive data in URL | P2 |
|
|
180
|
-
| `SELECT * FROM` in API handler without field filtering before response | Overly broad response | P3 |
|
|
181
|
-
| `fields = '__all__'` in serializer for user-facing API | Internal fields in response | P2 |
|
|
182
|
-
|
|
183
|
-
## Source
|
|
184
|
-
|
|
185
|
-
Derived from [secure-coding-failure.md](secure-coding-failure.md) section 4.8.
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
# Dependency Security Reference
|
|
2
|
-
|
|
3
|
-
*February 23, 2026*
|
|
4
|
-
|
|
5
|
-
Reference for AI agents reviewing dependency changes and supply chain risk.
|
|
6
|
-
Derived from [secure-coding-failure.md](secure-coding-failure.md) section 4.9.
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## Risk Model
|
|
11
|
-
|
|
12
|
-
### Direct Dependencies
|
|
13
|
-
- Explicitly chosen by the project (listed in `package.json`, `pyproject.toml`, etc.).
|
|
14
|
-
- Developer has evaluated fitness and should track updates.
|
|
15
|
-
|
|
16
|
-
### Transitive Dependencies
|
|
17
|
-
- Pulled in by direct deps. Often invisible to the developer.
|
|
18
|
-
- A vulnerability in a transitive dep can be exploitable even if the direct dep's API seems safe.
|
|
19
|
-
- Transitive deps are the primary source of surprise CVEs.
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Audit Tools
|
|
24
|
-
|
|
25
|
-
| Ecosystem | Tool | Command |
|
|
26
|
-
|-----------|------|---------|
|
|
27
|
-
| Node.js / pnpm | pnpm audit | `pnpm audit` |
|
|
28
|
-
| Node.js / npm | npm audit | `npm audit` |
|
|
29
|
-
| Node.js / yarn | yarn audit | `yarn audit` |
|
|
30
|
-
| Python | pip-audit | `pip-audit` |
|
|
31
|
-
| Python | safety | `safety check` |
|
|
32
|
-
| Multi-language | Snyk | `snyk test` |
|
|
33
|
-
| Multi-language | Trivy | `trivy fs .` |
|
|
34
|
-
|
|
35
|
-
Run the appropriate audit command during CI and before merging dependency changes.
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
|
|
39
|
-
## Risky Patterns to Flag
|
|
40
|
-
|
|
41
|
-
### Pinned Old Major Versions
|
|
42
|
-
- Direct dependency 3+ major versions behind latest.
|
|
43
|
-
- Older major versions often stop receiving security patches.
|
|
44
|
-
- Flag and recommend evaluating upgrade feasibility.
|
|
45
|
-
|
|
46
|
-
### Unmaintained Packages
|
|
47
|
-
- No commits or releases in 2+ years.
|
|
48
|
-
- No response to open security issues.
|
|
49
|
-
- Consider whether a maintained alternative exists.
|
|
50
|
-
|
|
51
|
-
### Packages with postinstall Scripts
|
|
52
|
-
- `postinstall` (and `preinstall`, `install`) scripts execute arbitrary code during `npm install` / `pnpm install`.
|
|
53
|
-
- A compromised or malicious package can use this to exfiltrate secrets or modify the filesystem.
|
|
54
|
-
- Flag any newly added dependency that includes lifecycle scripts.
|
|
55
|
-
|
|
56
|
-
### Typosquat Risk
|
|
57
|
-
- New or unfamiliar packages with names similar to popular packages.
|
|
58
|
-
- Check download counts, repository links, and publisher history.
|
|
59
|
-
- Examples: `lodahs` vs `lodash`, `coolor` vs `color`.
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
## What to Check on Lockfile Changes
|
|
64
|
-
|
|
65
|
-
When a PR modifies `pnpm-lock.yaml`, `package-lock.json`, `yarn.lock`, or
|
|
66
|
-
`requirements.txt` / `poetry.lock`, review the following:
|
|
67
|
-
|
|
68
|
-
| Change | Question | Risk |
|
|
69
|
-
|--------|----------|------|
|
|
70
|
-
| New direct dependency | Was this intentional and discussed? | Supply chain expansion |
|
|
71
|
-
| Version downgrade | Why was a version lowered? | May reintroduce patched CVE |
|
|
72
|
-
| New postinstall script | Does the new dep run code at install time? | Arbitrary code execution |
|
|
73
|
-
| Removed integrity hashes | Were `integrity` / `hash` fields deleted? | Tamper detection weakened |
|
|
74
|
-
| Large transitive tree addition | Does the new dep pull in many transitive deps? | Expanded attack surface |
|
|
75
|
-
| Dependency removed | Was the removal intentional? | May break functionality or remove security fix |
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## Triage Rules
|
|
80
|
-
|
|
81
|
-
| Condition | Severity |
|
|
82
|
-
|-----------|----------|
|
|
83
|
-
| Known CVE with active exploitation and RCE impact | P0 |
|
|
84
|
-
| Known CVE with high CVSS but no known active exploitation | P1 |
|
|
85
|
-
| Outdated dep, no known CVE but unmaintained | P2 |
|
|
86
|
-
| Missing audit in CI pipeline | P3 |
|
|
87
|
-
| New dep with postinstall script, no prior discussion | P2 |
|
|
88
|
-
|
|
89
|
-
## Source
|
|
90
|
-
|
|
91
|
-
Derived from [secure-coding-failure.md](secure-coding-failure.md) section 4.9.
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
# Injection Pattern Reference
|
|
2
|
-
|
|
3
|
-
*February 23, 2026*
|
|
4
|
-
|
|
5
|
-
Actionable patterns for detecting injection vulnerabilities during code review.
|
|
6
|
-
Covers SQL, Command, XSS, SSRF, and SSTI (survey sections 4.1-4.5).
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## SQL Injection (OWASP A03 -- P0/P1)
|
|
11
|
-
|
|
12
|
-
### Unsafe -- JS/TS
|
|
13
|
-
```typescript
|
|
14
|
-
// Template literal interpolation into SQL
|
|
15
|
-
const q = `SELECT * FROM users WHERE id = ${req.query.id}`;
|
|
16
|
-
db.query(q);
|
|
17
|
-
|
|
18
|
-
// String concatenation into SQL
|
|
19
|
-
db.query('SELECT * FROM users WHERE name = \'' + name + '\'');
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
### Safe -- JS/TS
|
|
23
|
-
```typescript
|
|
24
|
-
// Parameterized query
|
|
25
|
-
db.query('SELECT * FROM users WHERE id = $1', [req.query.id]);
|
|
26
|
-
|
|
27
|
-
// ORM with bound parameters (Knex example)
|
|
28
|
-
knex('users').where({ id: req.query.id });
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### better-sqlite3 (project-specific)
|
|
32
|
-
```typescript
|
|
33
|
-
// UNSAFE: db.exec() has NO parameterization support
|
|
34
|
-
db.exec(`INSERT INTO items VALUES ('${userInput}')`); // P0
|
|
35
|
-
|
|
36
|
-
// SAFE: Use db.prepare().run() with bound parameters
|
|
37
|
-
db.prepare('INSERT INTO items VALUES (?)').run(userInput);
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
### Unsafe -- Python
|
|
41
|
-
```python
|
|
42
|
-
# f-string in SQL
|
|
43
|
-
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
|
|
44
|
-
|
|
45
|
-
# Percent formatting in SQL
|
|
46
|
-
cursor.execute("SELECT * FROM users WHERE id = %s" % user_id)
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### Safe -- Python
|
|
50
|
-
```python
|
|
51
|
-
# Parameterized query
|
|
52
|
-
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
|
|
53
|
-
|
|
54
|
-
# ORM (SQLAlchemy)
|
|
55
|
-
session.query(User).filter(User.id == user_id).first()
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## Command Injection (OWASP A03 -- P0)
|
|
61
|
-
|
|
62
|
-
### Unsafe -- JS/TS
|
|
63
|
-
```typescript
|
|
64
|
-
// exec invokes shell, allows metacharacter injection
|
|
65
|
-
const { exec } = require('child_process');
|
|
66
|
-
exec('convert ' + req.query.file + ' output.png');
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Safe -- JS/TS
|
|
70
|
-
```typescript
|
|
71
|
-
// execFile bypasses shell, arguments are array elements
|
|
72
|
-
const { execFile } = require('child_process');
|
|
73
|
-
execFile('convert', [req.query.file, 'output.png']);
|
|
74
|
-
|
|
75
|
-
// spawn with explicit args array
|
|
76
|
-
const { spawn } = require('child_process');
|
|
77
|
-
spawn('convert', [req.query.file, 'output.png']);
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### Unsafe -- Python
|
|
81
|
-
```python
|
|
82
|
-
# shell=True allows metacharacter injection
|
|
83
|
-
import subprocess
|
|
84
|
-
subprocess.run("tar xf " + archive_name, shell=True)
|
|
85
|
-
|
|
86
|
-
# os.system always invokes shell
|
|
87
|
-
import os
|
|
88
|
-
os.system("tar xf " + archive_name)
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### Safe -- Python
|
|
92
|
-
```python
|
|
93
|
-
# shell=False (default), args as list
|
|
94
|
-
import subprocess
|
|
95
|
-
subprocess.run(["tar", "xf", archive_name])
|
|
96
|
-
|
|
97
|
-
# shlex.quote if shell is unavoidable (rare, last resort)
|
|
98
|
-
import shlex
|
|
99
|
-
subprocess.run(f"tar xf {shlex.quote(archive_name)}", shell=True)
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
## Cross-Site Scripting / XSS (OWASP A03 -- P1)
|
|
105
|
-
|
|
106
|
-
### Unsafe -- JS/TS
|
|
107
|
-
```typescript
|
|
108
|
-
// Direct innerHTML assignment
|
|
109
|
-
element.innerHTML = userInput;
|
|
110
|
-
|
|
111
|
-
// Raw HTML in response
|
|
112
|
-
res.send('<div>' + req.query.name + '</div>');
|
|
113
|
-
|
|
114
|
-
// React escape hatch
|
|
115
|
-
<div dangerouslySetInnerHTML={{ __html: userInput }} />
|
|
116
|
-
|
|
117
|
-
// Vue escape hatch
|
|
118
|
-
<div v-html="userInput"></div>
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### Safe -- JS/TS
|
|
122
|
-
```typescript
|
|
123
|
-
// textContent does not parse HTML
|
|
124
|
-
element.textContent = userInput;
|
|
125
|
-
|
|
126
|
-
// Framework auto-escaping (React default)
|
|
127
|
-
<div>{userInput}</div>
|
|
128
|
-
|
|
129
|
-
// DOMPurify for cases requiring HTML
|
|
130
|
-
import DOMPurify from 'dompurify';
|
|
131
|
-
element.innerHTML = DOMPurify.sanitize(userInput);
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### Unsafe -- Python (Jinja2/Django)
|
|
135
|
-
```python
|
|
136
|
-
# Marking user input as safe bypasses auto-escaping
|
|
137
|
-
{{ user_input | safe }}
|
|
138
|
-
|
|
139
|
-
# Disabling auto-escape globally
|
|
140
|
-
app.jinja_env.autoescape = False
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Safe -- Python (Jinja2/Django)
|
|
144
|
-
```python
|
|
145
|
-
# Default auto-escaping (leave it enabled)
|
|
146
|
-
{{ user_input }}
|
|
147
|
-
|
|
148
|
-
# Explicit escaping if autoescape is off for some reason
|
|
149
|
-
{{ user_input | e }}
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
---
|
|
153
|
-
|
|
154
|
-
## Server-Side Request Forgery / SSRF (OWASP A10 -- P1, escalate to P0 for cloud metadata)
|
|
155
|
-
|
|
156
|
-
### Unsafe -- JS/TS
|
|
157
|
-
```typescript
|
|
158
|
-
// User-controlled URL passed directly to HTTP client
|
|
159
|
-
const response = await axios.get(req.query.url);
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### Safe -- JS/TS
|
|
163
|
-
```typescript
|
|
164
|
-
// Allowlist validation before request
|
|
165
|
-
const ALLOWED_HOSTS = new Set(['api.example.com', 'cdn.example.com']);
|
|
166
|
-
const parsed = new URL(req.query.url);
|
|
167
|
-
if (!ALLOWED_HOSTS.has(parsed.hostname)) {
|
|
168
|
-
return res.status(400).json({ error: 'Host not allowed' });
|
|
169
|
-
}
|
|
170
|
-
const response = await axios.get(parsed.toString());
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### Unsafe -- Python
|
|
174
|
-
```python
|
|
175
|
-
# User-controlled URL with no validation
|
|
176
|
-
import requests
|
|
177
|
-
resp = requests.get(request.args['url'])
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### Safe -- Python
|
|
181
|
-
```python
|
|
182
|
-
# Allowlist validation
|
|
183
|
-
from urllib.parse import urlparse
|
|
184
|
-
|
|
185
|
-
ALLOWED_HOSTS = {'api.example.com', 'cdn.example.com'}
|
|
186
|
-
parsed = urlparse(request.args['url'])
|
|
187
|
-
if parsed.hostname not in ALLOWED_HOSTS:
|
|
188
|
-
abort(400, 'Host not allowed')
|
|
189
|
-
resp = requests.get(request.args['url'])
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
---
|
|
193
|
-
|
|
194
|
-
## Server-Side Template Injection / SSTI (OWASP A03 -- P0)
|
|
195
|
-
|
|
196
|
-
### Unsafe -- JS/TS (Nunjucks example)
|
|
197
|
-
```typescript
|
|
198
|
-
// User input as template source -- attacker controls template syntax
|
|
199
|
-
const nunjucks = require('nunjucks');
|
|
200
|
-
const output = nunjucks.renderString(req.body.template, { data: someData });
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
### Safe -- JS/TS
|
|
204
|
-
```typescript
|
|
205
|
-
// User input as data only, template is a constant
|
|
206
|
-
const nunjucks = require('nunjucks');
|
|
207
|
-
const output = nunjucks.render('page.njk', { data: req.body.data });
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Unsafe -- Python (Jinja2)
|
|
211
|
-
```python
|
|
212
|
-
# User input compiled as template source
|
|
213
|
-
from jinja2 import Template
|
|
214
|
-
output = Template(user_input).render()
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
### Safe -- Python (Jinja2)
|
|
218
|
-
```python
|
|
219
|
-
# Constant template, user input as render data only
|
|
220
|
-
from jinja2 import Template
|
|
221
|
-
output = Template("Hello {{ name }}").render(name=user_input)
|
|
222
|
-
|
|
223
|
-
# Or use SandboxedEnvironment for extra protection
|
|
224
|
-
from jinja2.sandbox import SandboxedEnvironment
|
|
225
|
-
env = SandboxedEnvironment()
|
|
226
|
-
template = env.from_string("Hello {{ name }}")
|
|
227
|
-
output = template.render(name=user_input)
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
---
|
|
231
|
-
|
|
232
|
-
## Detection Heuristics Summary
|
|
233
|
-
|
|
234
|
-
| API / Pattern | Language | Risk Level | Injection Type |
|
|
235
|
-
|---------------|----------|------------|----------------|
|
|
236
|
-
| `db.query` with template literal or concat | JS/TS | HIGH | SQL |
|
|
237
|
-
| `cursor.execute` with f-string or `%` format | Python | HIGH | SQL |
|
|
238
|
-
| `child_process.exec` with user input | JS/TS | HIGH | Command |
|
|
239
|
-
| `os.system`, `subprocess.run(..., shell=True)` with user input | Python | HIGH | Command |
|
|
240
|
-
| `innerHTML` assignment from user input | JS/TS | MEDIUM | XSS |
|
|
241
|
-
| `dangerouslySetInnerHTML`, `v-html` | JS/TS | MEDIUM | XSS |
|
|
242
|
-
| `{{ var \| safe }}` with user-sourced var | Python | MEDIUM | XSS |
|
|
243
|
-
| `axios.get(req.query.url)`, `requests.get(user_url)` | Both | HIGH | SSRF |
|
|
244
|
-
| `Template(user_input)` or `renderString(user_input, ...)` | Both | HIGH | SSTI |
|
|
245
|
-
| `eval()`, `new Function()` with user input | JS/TS | HIGH | Code injection |
|
|
246
|
-
|
|
247
|
-
## Source
|
|
248
|
-
|
|
249
|
-
Derived from [secure-coding-failure.md](secure-coding-failure.md) sections 4.1-4.5.
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# Security Review Overview
|
|
2
|
-
|
|
3
|
-
*February 23, 2026*
|
|
4
|
-
|
|
5
|
-
Quick-reference guide for AI code review agents performing security triage.
|
|
6
|
-
Distilled from [secure-coding-failure.md](secure-coding-failure.md) (survey section 4.10).
|
|
7
|
-
|
|
8
|
-
## Severity Classification
|
|
9
|
-
|
|
10
|
-
| Level | Label | Description | Examples |
|
|
11
|
-
|-------|-------|-------------|----------|
|
|
12
|
-
| **P0** | Critical | Unauthenticated RCE, credential compromise, mass data breach | Unauth command injection, leaked production DB credentials, unauth SQL injection yielding full table dump |
|
|
13
|
-
| **P1** | High | Auth-required exploit, targeted data breach, privilege escalation | Authenticated SQLi, IDOR exposing other users' data, JWT signature bypass |
|
|
14
|
-
| **P2** | Medium | Harder to exploit, limited blast radius | Reflected XSS requiring user interaction, SSRF blocked by network policy but code-level vuln present |
|
|
15
|
-
| **P3** | Hardening | Best practice gap, defense-in-depth improvement | Missing rate limiting, verbose error messages in staging, outdated dep with no known exploit path |
|
|
16
|
-
|
|
17
|
-
## OWASP Category to Default Severity
|
|
18
|
-
|
|
19
|
-
| OWASP Category | Default Severity | Escalation Condition |
|
|
20
|
-
|----------------|-----------------|----------------------|
|
|
21
|
-
| A01 Broken Access Control | P1 | Escalate to P0 if unauthenticated access to admin or sensitive data |
|
|
22
|
-
| A02 Cryptographic Failures | P1 | Escalate to P0 if plaintext credentials stored or transmitted |
|
|
23
|
-
| A03 Injection (SQL/Cmd/XSS/SSTI) | P0 (RCE) or P1 (data-only) | P0 if command/template injection yields RCE; P1 if SQLi yields data leak only |
|
|
24
|
-
| A04 Insecure Design | P2 | Escalate to P1 if missing security controls enable auth bypass |
|
|
25
|
-
| A05 Security Misconfiguration | P2 | Escalate to P1 if default credentials or debug mode exposed in production |
|
|
26
|
-
| A06 Vulnerable Components | P2 | Escalate to P0/P1 if CVE is actively exploited or yields RCE |
|
|
27
|
-
| A07 Auth Failures | P1 | Escalate to P0 if credential stuffing or brute force is trivially possible |
|
|
28
|
-
| A08 Software/Data Integrity Failures | P2 | Escalate to P0 if CI/CD pipeline compromise or unsigned updates possible |
|
|
29
|
-
| A09 Security Logging Failures | P3 | Escalate to P2 if no logging on auth events or admin actions |
|
|
30
|
-
| A10 SSRF | P1 | Escalate to P0 if cloud metadata endpoint (169.254.169.254) is reachable |
|
|
31
|
-
|
|
32
|
-
## Escalation Triggers
|
|
33
|
-
|
|
34
|
-
When the review agent detects one of the following patterns, it should invoke the
|
|
35
|
-
corresponding specialist skill for deeper analysis.
|
|
36
|
-
|
|
37
|
-
### /security-injection
|
|
38
|
-
Trigger when:
|
|
39
|
-
- String concatenation or template interpolation inside a SQL query
|
|
40
|
-
- `child_process.exec` or `os.system` called with user-derived arguments
|
|
41
|
-
- Template engine receives user input as the template source (not data)
|
|
42
|
-
|
|
43
|
-
### /security-secrets
|
|
44
|
-
Trigger when:
|
|
45
|
-
- Hardcoded strings matching API key or token patterns (see [secrets-checklist.md](secrets-checklist.md))
|
|
46
|
-
- `.env` files tracked in git
|
|
47
|
-
- Variables named `password`, `secret`, `token`, `apiKey` assigned string literals
|
|
48
|
-
|
|
49
|
-
### /security-auth
|
|
50
|
-
Trigger when:
|
|
51
|
-
- Route handlers missing auth middleware present on sibling routes
|
|
52
|
-
- Database queries using user-supplied IDs without ownership filter
|
|
53
|
-
- CORS configured with `origin: '*'` alongside `credentials: true`
|
|
54
|
-
|
|
55
|
-
### /security-data
|
|
56
|
-
Trigger when:
|
|
57
|
-
- Logging calls receive entire request objects (`console.log(req.body)`)
|
|
58
|
-
- Error handlers pass `err.stack` or `err.message` directly to HTTP response
|
|
59
|
-
- Tokens or PII appear in URL query parameters
|
|
60
|
-
|
|
61
|
-
### /security-deps
|
|
62
|
-
Trigger when:
|
|
63
|
-
- Lockfile changes introduce new direct dependencies
|
|
64
|
-
- Package version downgrades appear in diffs
|
|
65
|
-
- Packages with `postinstall` scripts are added
|
|
66
|
-
- Dependencies are 3+ major versions behind latest
|
|
67
|
-
|
|
68
|
-
## Domain-Specific References
|
|
69
|
-
|
|
70
|
-
| Domain | Reference Document |
|
|
71
|
-
|--------|--------------------|
|
|
72
|
-
| Injection (SQL, Cmd, XSS, SSRF, SSTI) | [injection-patterns.md](injection-patterns.md) |
|
|
73
|
-
| Secrets and credentials | [secrets-checklist.md](secrets-checklist.md) |
|
|
74
|
-
| Authentication and authorization | [auth-patterns.md](auth-patterns.md) |
|
|
75
|
-
| Data exposure and logging | [data-exposure.md](data-exposure.md) |
|
|
76
|
-
| Dependency and supply chain | [dependency-security.md](dependency-security.md) |
|
|
77
|
-
|
|
78
|
-
## Source
|
|
79
|
-
|
|
80
|
-
All patterns derived from the research survey:
|
|
81
|
-
[secure-coding-failure.md](secure-coding-failure.md) -- sections 4.1-4.10 and comparative synthesis.
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
# Secrets Detection Checklist
|
|
2
|
-
|
|
3
|
-
*February 23, 2026*
|
|
4
|
-
|
|
5
|
-
Reference for AI agents performing secret detection during code review.
|
|
6
|
-
Derived from [secure-coding-failure.md](secure-coding-failure.md) section 4.6.
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## What Counts as a Secret
|
|
11
|
-
|
|
12
|
-
**Flag these:**
|
|
13
|
-
- API keys and access tokens (AWS, GCP, Azure, GitHub, Slack, Stripe, etc.)
|
|
14
|
-
- Passwords and passphrases
|
|
15
|
-
- Private keys (RSA, EC, PGP)
|
|
16
|
-
- Database connection strings with credentials
|
|
17
|
-
- JWT signing secrets
|
|
18
|
-
- Webhook secrets and HMAC keys
|
|
19
|
-
- OAuth client secrets
|
|
20
|
-
|
|
21
|
-
**Ignore these (not secrets):**
|
|
22
|
-
- Test fixtures prefixed with `test_`, `fake_`, `mock_`, `dummy_`
|
|
23
|
-
- Example placeholders: `YOUR_API_KEY_HERE`, `xxx`, `changeme`, `REPLACE_ME`
|
|
24
|
-
- Public keys (designed to be shared)
|
|
25
|
-
- Hash algorithm names or constants (`sha256`, `aes-256-cbc`)
|
|
26
|
-
- Empty strings assigned to secret-named variables (skeleton config)
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Common Hiding Spots
|
|
31
|
-
|
|
32
|
-
| Location | Detection Method |
|
|
33
|
-
|----------|-----------------|
|
|
34
|
-
| Source code (`.ts`, `.js`, `.py`) | Scan string literals and variable assignments |
|
|
35
|
-
| `.env` files committed to git | Check if `.env` is tracked (should be in `.gitignore`) |
|
|
36
|
-
| CI/CD config (`.github/workflows/*.yml`, `.gitlab-ci.yml`) | Scan for inline secrets vs `${{ secrets.X }}` references |
|
|
37
|
-
| Docker files (`Dockerfile`, `docker-compose.yml`) | Check `ENV` and `ARG` directives for credential values |
|
|
38
|
-
| Git history | Secrets removed from HEAD may persist in older commits |
|
|
39
|
-
| Config files (`config.json`, `settings.py`) | Scan for credential fields with literal values |
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## Known Key Format Patterns
|
|
44
|
-
|
|
45
|
-
| Provider / Type | Regex Pattern |
|
|
46
|
-
|----------------|---------------|
|
|
47
|
-
| AWS Access Key | `AKIA[0-9A-Z]{16}` |
|
|
48
|
-
| AWS Secret Key | 40-char base64 string near `aws_secret_access_key` |
|
|
49
|
-
| GitHub PAT | `ghp_[a-zA-Z0-9]{36}` |
|
|
50
|
-
| GitHub OAuth | `gho_[a-zA-Z0-9]{36}` |
|
|
51
|
-
| GitHub App | `ghs_[a-zA-Z0-9]{36}` |
|
|
52
|
-
| Slack Bot Token | `xoxb-[0-9]+-[0-9a-zA-Z]+` |
|
|
53
|
-
| Slack User Token | `xoxp-[0-9]+-[0-9a-zA-Z]+` |
|
|
54
|
-
| Stripe Secret Key | `sk_live_[a-zA-Z0-9]{24,}` |
|
|
55
|
-
| Stripe Publishable | `pk_live_[a-zA-Z0-9]{24,}` (lower risk, still flag) |
|
|
56
|
-
| Google API Key | `AIza[0-9A-Za-z_-]{35}` |
|
|
57
|
-
| Private Key Header | `-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----` |
|
|
58
|
-
| Generic high-entropy | 20+ chars, mixed case + digits + special, not a known non-secret format |
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
## Variable Name Patterns to Flag
|
|
63
|
-
|
|
64
|
-
Scan assignment targets and object property names for these patterns (case-insensitive):
|
|
65
|
-
|
|
66
|
-
- `password`, `passwd`, `pwd`
|
|
67
|
-
- `secret`, `secret_key`, `secretKey`
|
|
68
|
-
- `token`, `access_token`, `accessToken`, `auth_token`
|
|
69
|
-
- `api_key`, `apiKey`, `api_secret`
|
|
70
|
-
- `credential`, `credentials`
|
|
71
|
-
- `private_key`, `privateKey`
|
|
72
|
-
- `connection_string`, `connectionString`, `database_url`, `databaseUrl`
|
|
73
|
-
- `signing_key`, `signingKey`, `hmac_key`
|
|
74
|
-
|
|
75
|
-
When a flagged variable name is assigned a string literal (not an env var reference or
|
|
76
|
-
placeholder), report it. If the value also matches a known key pattern, escalate to P0.
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## Triage Rules
|
|
81
|
-
|
|
82
|
-
| Condition | Severity |
|
|
83
|
-
|-----------|----------|
|
|
84
|
-
| Known provider key format + production context | P0 |
|
|
85
|
-
| Generic high-entropy string in secret-named variable | P1 |
|
|
86
|
-
| `.env` file committed with credential values | P1 |
|
|
87
|
-
| Secret in CI config as inline value (not a secret ref) | P1 |
|
|
88
|
-
| Secret-named variable assigned a placeholder or empty string | P3 (informational) |
|
|
89
|
-
|
|
90
|
-
## Source
|
|
91
|
-
|
|
92
|
-
Derived from [secure-coding-failure.md](secure-coding-failure.md) section 4.6.
|