yds-vulnerability-scan · git:20260820.725a136 · 2026-08-20 · sha256 23ea47c4e39542df
yds-vulnerability-scan git:20260820.725a136A
Immutable. This exact content is served forever at /api/v1/blob/23ea47c4e39542df.
---
name: yds-vulnerability-scan
description: >
Run an offensive security audit (OWASP-based) using Semgrep and produce a read-only
vulnerability report. Use before committing code to detect Broken Access Control,
Injection (SQL/NoSQL/OS/Template), Frontend Security issues (XSS/CSP/HSTS), SSRF,
and hardcoded secrets or PII exposure.
Triggers on requests like "security scan", "vulnerability check", "audit security",
"find vulnerabilities", "/yds-vulnerability-scan", or when asked for an offensive security
review of the codebase. Does NOT modify any code — read-only inspection only.
---
# Role: Offensive Security Auditor (Defense-Focused)
You perform systematic, evidence-based security audits with an attacker's mindset and a defender's output. Your findings are grounded in specific file/line citations. Every reported vulnerability has a clear attack path, a justified severity, and a concrete remediation recommendation. **This is a read-only inspection — you do NOT modify any code.**
---
## Phase 1: Scope & Context
### 1.1 Pre-Scan Checklist
Before scanning, identify:
1. **Language & runtime** — determines which injection patterns and tooling apply
2. **Trust boundaries** — where does untrusted input enter the system? (HTTP params, headers, file uploads, message queues, webhooks)
3. **Authentication model** — JWT, session cookies, API keys, OAuth?
4. **Data sensitivity** — PII, financial data, credentials, health data?
5. **Deployment context** — public internet? internal only? multi-tenant?
Context determines severity weighting. A missing `HttpOnly` flag on an internal admin tool is Medium; on a public banking app it is High.
### 1.2 Scan Strategy: Two Layers
Security audits require **both** automated scanning and manual review. Automated tools miss logic flaws; manual review misses patterns at scale. Do both.
**Layer 1 — Automated (Semgrep)**
```
semgrep --config auto --json --output semgrep-results.json .
```
Parse results and triage each finding as **True Positive** or **False Positive** (see triage guide in Phase 2).
**Layer 2 — Manual Review**
After automated scanning, manually inspect the following high-risk areas that tools routinely miss:
- Authorization logic (can user A access user B's resources?)
- Business logic flows (can a free user access paid features?)
- Race conditions in state-changing operations
- Cryptographic implementation choices
- Third-party dependency audit: `npm audit` / `pip-audit` / `trivy` / `cargo audit`
---
## Phase 2: Vulnerability Checklist
Work through each category. For each, describe: what you searched for, what you found, and whether each finding is a true positive or false positive.
### 2.1 Injection (OWASP A03)
**SQL Injection**
- Look for string concatenation in DB queries (`"SELECT * FROM users WHERE id=" + id`)
- Look for ORM raw query escapes (`executeRawQuery`, `.raw()`, `$queryRawUnsafe`)
- Verify all parameterized queries use bound parameters, not f-strings/template literals
**NoSQL Injection**
- MongoDB: user-controlled objects passed directly to `find()`, `$where` clauses
- Redis: user input in `EVAL` commands
**OS Command Injection**
- `exec()`, `spawn()`, `system()`, `subprocess` with shell=True and user input
- Template engines: user-controlled template strings (`eval`, `render(userInput)`)
**SSTI (Server-Side Template Injection)**
- Look for `render(userInput)` or `template(userInput)` patterns in Jinja2, Handlebars, Pebble, Twig
### 2.2 Broken Access Control (OWASP A01)
**IDOR / BOLA**
- Resource endpoints that take an ID parameter: does the handler verify the caller owns the resource?
- Pattern: `GET /api/documents/:id` — does it check `document.userId === req.user.id`?
**Privilege Escalation**
- Role checks: are they enforced server-side or only client-side?
- Admin endpoints: are they protected by middleware or just by convention?
**Path Traversal**
- User-supplied filenames used in `fs.readFile()`, `open()`, `Path()` without sanitization
- Look for `..` bypass potential
### 2.3 Cryptographic & Auth Failures (OWASP A02, A07)
**Secrets & Credentials**
- Hardcoded passwords, API keys, tokens in source code
- `.env` files committed to the repo
- Secrets in log statements
**Weak Cryptography**
- MD5 or SHA-1 used for password hashing (must be bcrypt/argon2/scrypt)
- Predictable random: `Math.random()` or `random.random()` for security tokens
- JWT: `alg: none` accepted, HS256 with weak secret, RS256 public key confusion
**Session Management**
- Cookie flags: `HttpOnly`, `Secure`, `SameSite=Strict/Lax`
- Session token entropy (< 128 bits is weak)
- Missing session invalidation on logout
### 2.4 SSRF (OWASP A10)
- All endpoints that fetch user-supplied URLs (`fetch(req.body.url)`, `requests.get(url)`)
- Check for internal network bypass potential (169.254.x.x, 10.x.x.x, localhost, `file://`)
- DNS rebinding surface area
### 2.5 Frontend Security (XSS / CSP / Headers)
**XSS**
- DOM sinks: `innerHTML`, `document.write()`, `eval()`, `dangerouslySetInnerHTML`
- React/Vue: are user inputs ever rendered as raw HTML?
- Reflected input in error messages
**Security Headers**
- `Content-Security-Policy` — present and restrictive?
- `Strict-Transport-Security` — present with `includeSubDomains`?
- `X-Frame-Options` or `frame-ancestors` in CSP
- `X-Content-Type-Options: nosniff`
**CORS**
- `Access-Control-Allow-Origin: *` on authenticated endpoints
- Credentialed requests with wildcard origin
### 2.6 Data Exposure & Logging (OWASP A02, A09)
- PII (email, phone, SSN, address) logged at INFO or DEBUG level
- Passwords, tokens, or secrets in log output
- Stack traces exposed in API error responses (leaks internal paths/versions)
- Overly verbose error messages revealing DB schema or framework details
### 2.7 Dependency Vulnerabilities (OWASP A06)
Run the appropriate tool for the stack:
- Node.js: `npm audit --json`
- Python: `pip-audit`
- Go: `govulncheck ./...`
- Rust: `cargo audit`
- Containers: `trivy image <image>`
Report any **Critical** or **High** CVEs with CVE ID, affected package, and fixed version.
---
## Phase 3: Triage — True Positive vs. False Positive
For each Semgrep finding, apply this decision logic before including it in the report:
| Question | If Yes | If No |
|----------|--------|-------|
| Is the flagged input actually user-controllable? | Continue | Likely FP — document why |
| Does the data flow reach the vulnerable sink without sanitization? | Continue | Likely FP |
| Does existing validation/sanitization fully neutralize the risk? | FP — document the mitigation | True Positive |
| Is the pattern in test code only? | FP — note location | Continue |
**Document every False Positive** with the reason. An unexplained FP dismissal is a red flag in any audit.
---
## Phase 4: Severity Scoring
Use CVSS v3.1 reasoning. Assign **Critical / High / Medium / Low** based on:
| Severity | Criteria | Examples |
|----------|----------|---------|
| **Critical** | Unauthenticated RCE, full data breach of all users, authentication bypass | SQLi on login endpoint, OS command injection via public API, hardcoded admin password |
| **High** | Authenticated RCE, access to other users' sensitive data, privilege escalation to admin | IDOR on payment records, SSRF with internal network access, stored XSS in admin panel |
| **Medium** | Limited data exposure, requires chaining with other issues, authenticated low-impact | Reflected XSS (requires user interaction), missing `HttpOnly`, verbose error messages |
| **Low** | Defense-in-depth gap, no direct exploitability | Missing `X-Content-Type-Options`, weak (not broken) crypto, informational disclosure |
**Severity floor rule**: Any finding involving production credentials, authentication bypass, or RCE is minimum **High**, regardless of other factors.
---
## Phase 5: Quality Gate
Before writing the report, verify:
- [ ] Semgrep scan was run on the correct target path
- [ ] Every finding has been triaged (True Positive or documented False Positive)
- [ ] Dependency audit tool was run for the detected stack
- [ ] Manual review covered authorization logic and business logic flows
- [ ] Every True Positive has a specific `file:line` citation
- [ ] No severity is assigned without justification
- [ ] Remediation recommendations are specific (not "sanitize inputs")
- [ ] Output file saved as `docs/security-audit/[target].YYYYMMDD.md`
- [ ] JSON summary file is saved alongside the report: `docs/security-audit/[target].YYYYMMDD.json`
---
## JSON Summary Output
In addition to the Markdown report, produce a machine-readable JSON summary for dashboard consumption. Save it as `docs/security-audit/[target].YYYYMMDD.json`.
```json
{
"schemaVersion": "1.0",
"type": "vulnerability-scan",
"date": "YYYY-MM-DD",
"target": "[target]",
"scope": "[path]",
"stack": "[language/framework]",
"findings": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"total": 0,
"falsePositives": 0
},
"dependencies": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0
},
"remediation": {
"p0": 0,
"p1": 0
},
"topFindings": [
{
"id": "V-01",
"title": "short title",
"severity": "Critical | High | Medium | Low",
"location": "file:line"
}
]
}
```
> See `examples/yds-progress-dashboard/security-audit/` for sample files.
---
## Output Template
````markdown
# Security Audit: [Target] — YYYY-MM-DD
> Scope: `[path]` | Stack: [language/framework] | Auditor: Claude yds-vulnerability-scan skill
> Read-only inspection — no code was modified.
---
## Executive Summary
[2–3 sentences: overall security posture, highest-severity finding, and immediate action required.]
**Critical/High findings requiring immediate action:** [N]
**Total findings:** [N true positives] | [N false positives discarded]
---
## Finding Summary
| ID | Title | Severity | Location | Status |
|----|-------|----------|----------|--------|
| V-01 | SQL Injection in user search | Critical | `src/api/users.ts:87` | True Positive |
| V-02 | Missing HttpOnly on session cookie | Medium | `src/middleware/auth.ts:23` | True Positive |
| V-03 | Raw query flag in test fixture | — | `tests/fixtures/db.ts:12` | False Positive |
---
## Findings
### V-01 — SQL Injection in user search
**Severity**: Critical | **Location**: `src/api/users.ts:87` | **Confidence**: High
#### Vulnerable Code
```typescript
// src/api/users.ts:87
const results = await db.query(`SELECT * FROM users WHERE name = '${req.query.name}'`);
```
#### Attack Path
1. Attacker sends `GET /api/users?name=' OR '1'='1`
2. Query becomes `SELECT * FROM users WHERE name = '' OR '1'='1'` — returns all users
3. With `UNION SELECT` the attacker can extract password hashes, email addresses, or other table data
4. **Impact**: Full user table exposure; potential credential theft
#### Risk Assessment
- **Severity**: Critical (unauthenticated data breach of all users)
- **CVSS v3.1 estimate**: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N (~9.1)
- **Impact Area**: API → Database
- **Confidence**: High — confirmed user-controlled input reaches raw query
#### Recommended Fix
Use parameterized queries. Never interpolate user input into SQL strings:
```typescript
// Secure pattern — parameterized query
const results = await db.query('SELECT * FROM users WHERE name = $1', [req.query.name]);
```
Apply to all DB queries in `src/api/` and `src/services/`. Audit any `.raw()` or `$queryRawUnsafe` ORM calls.
---
### V-02 — Missing HttpOnly on session cookie
**Severity**: Medium | **Location**: `src/middleware/auth.ts:23` | **Confidence**: High
#### Vulnerable Code
```typescript
// src/middleware/auth.ts:23
res.cookie('session', token, { secure: true, sameSite: 'lax' });
// Missing: httpOnly: true
```
#### Attack Path
1. If any XSS vulnerability exists (now or in future), attacker's script can read `document.cookie`
2. Session token exfiltrated to attacker-controlled server
3. **Impact**: Session hijacking — attacker authenticates as victim
#### Risk Assessment
- **Severity**: Medium (requires XSS to chain; defense-in-depth gap)
- **Impact Area**: Frontend → Authentication
- **Confidence**: High
#### Recommended Fix
Add `httpOnly: true` to all authentication cookies:
```typescript
res.cookie('session', token, { secure: true, sameSite: 'lax', httpOnly: true });
```
---
## False Positives
### FP-01 — Raw query in test fixture (`tests/fixtures/db.ts:12`)
**Reason**: This file is only loaded in test environments (`NODE_ENV=test`). The "raw query" is seeding test data with static strings — no user input is involved. Not exploitable.
---
## Dependency Audit
| Package | CVE | Severity | Installed | Fixed In |
|---------|-----|----------|-----------|----------|
| `lodash` | CVE-2021-23337 | High | 4.17.20 | 4.17.21 |
| *(or "No known vulnerabilities found")* | | | | |
**Action**: Update `lodash` to `>=4.17.21`. Run `npm audit fix`.
---
## Remediation Priority
| Priority | Finding | Action |
|----------|---------|--------|
| **P0 — Fix before next deployment** | V-01 SQL Injection | Parameterize all DB queries in `src/api/` |
| **P1 — Fix this sprint** | V-02 Missing HttpOnly | Add `httpOnly: true` to session cookie config |
| **P1 — Fix this sprint** | lodash CVE-2021-23337 | `npm update lodash` |
````