# Yds Vulnerability Scan

> 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.

- Skill: `ymd38/yds-vulnerability-scan` (Agent Skill)
- Install (CLI): `npx skillmds@latest add ymd38/yds-vulnerability-scan`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ymd38/yds-vulnerability-scan/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: ymd38 (https://skillmd.com/u/ymd38)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ymd38/yds-vulnerability-scan

---


# 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` |
````

