# Scan Security

> Detects security vulnerabilities via static pattern matching based on OWASP Top 10

- Skill: `ww-w-ai/scan-security` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add ww-w-ai/scan-security`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ww-w-ai/scan-security/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: ww-w-ai (https://skillmd.com/u/ww-w-ai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ww-w-ai/scan-security

---


# scan-security -- OWASP-Based Security Vulnerability Detection

Corresponding rule: `security.md`

## Purpose

Detect security vulnerabilities in code via static pattern matching based on OWASP Top 10. Does not auto-fix; reports only suspected items.

## Input -- Dynamic Target Resolution

Resolve target directories in this order:
1. CLAUDE.md "Project Structure" section -- extract source code directories
2. If CLAUDE.md is missing or has no structure info: Glob source files (`**/*.{ts,tsx,js,jsx,py,java,go,rs}`) -- use the top-level directory containing matched files
3. If no source files are found: report status as SHALLOW and state the reason

Default exclusions: node_modules/, .git/, dist/, build/, coverage/
Skill-specific exclusions: `*.test.*`, `*.spec.*`, `test_*`, `*_test.*` (security test code excluded)

### Mandatory Output: Target Resolution Result

Output the following before proceeding with validation. Do not advance until resolution is complete.

| Step | Result |
|------|--------|
| CLAUDE.md check | Found/Not found |
| Resolved directories | {list or "none"} |
| Source file count | {count} |
| Resolution method | CLAUDE.md / Glob fallback / SHALLOW |

## Validation Categories

### 1. Hardcoded Secrets

Detect passwords, API keys, and tokens embedded directly in code.

Search patterns:
- `API_KEY\s*=\s*["']`
- `password\s*=\s*["']`
- `secret\s*=\s*["']`
- `token\s*=\s*["']`
- `PRIVATE_KEY\s*=\s*["']`
- `aws_access_key_id\s*=\s*["']`
- `aws_secret_access_key\s*=\s*["']`

Severity: **CRITICAL**

### 2. SQL Injection

Detect patterns that build SQL queries via string interpolation.

Search patterns:
- `f"SELECT`
- `f"INSERT`
- `f"UPDATE`
- `f"DELETE`
- `f"DROP`
- `` `SELECT.*\$\{` `` (SQL in template literals)
- `"SELECT.*" \+` (SQL via string concatenation)

Severity: **CRITICAL**

### 3. XSS (Cross-Site Scripting)

Detect patterns that inject user input into HTML without escaping.

Search patterns:
- `innerHTML\s*=`
- `dangerouslySetInnerHTML`
- `v-html=`
- `\{!!.*!!\}` (Blade unescaped output)
- `\|safe` (Django/Jinja safe filter)

Severity: **HIGH**

### 4. Command Injection

Detect patterns that pass external input directly to shell commands.

Search patterns:
- `os.system(f"`
- `subprocess.*shell=True`
- `exec(` (dynamic code execution)
- `eval(` (dynamic code execution)
- `` child_process.exec(`.* `` (Node.js)

Severity: **CRITICAL**

### 5. Error Information Exposure

Detect patterns that include internal system information in user responses.

Search patterns:
- `traceback.format_exc()` -- near return/response
- `str(e)` -- included directly in the response object
- `stack.*trace` -- included in the response
- `exc_info=True` -- inside a user-response function

Severity: **MEDIUM**

### 6. .gitignore Check

Verify that secret files are included in .gitignore.

Required patterns (must exist in .gitignore):
- `.env` related: `.env`, `.env.*`, `.env.local`
- Credential files: `credentials`, `credentials.*`
- Key files: `*.pem`, `*.key`, `*.p12`, `*.pfx`
- Secret directories: `secrets/`, `.secrets/`

Severity: **HIGH** when missing

## Execution Logic

1. `Glob` to collect target source files (excluding test files)
2. Categories 1-5: `Grep` each category's patterns across all source files
3. Category 6: `Read` the `.gitignore` file and check for required patterns
4. Sort detected items by severity and output as a table

### Mandatory Output: Security Scan Verification Matrix

Output the matrix below before generating the final report. Do not proceed until every category has been scanned.

| Category | Status | Items Checked | Findings | Severity | Evidence |
|----------|:------:|:-------------:|:--------:|:--------:|----------|
| Hardcoded Secrets | ? | ? | ? | CRITICAL | {tool, files, pattern} |
| SQL Injection | ? | ? | ? | CRITICAL | {tool, files, pattern} |
| XSS | ? | ? | ? | HIGH | {tool, files, pattern} |
| Command Injection | ? | ? | ? | CRITICAL | {tool, files, pattern} |
| Error Information Exposure | ? | ? | ? | MEDIUM | {tool, files, pattern} |
| .gitignore | ? | ? | ? | HIGH | {tool, files, pattern} |

Status values: PASS (verification complete, no issues), NOT_APPLICABLE (no source files), SKIPPED (plugin issue), SHALLOW (target resolution failed)

### Pre-Output Checklist (Mandatory Before Final Output)

Check every item before writing the report. If any item is unchecked, go back and complete it.

- [ ] Every validation category has a Status value (no empty Status cells)
- [ ] Every category with Status != SKIPPED has an Evidence value
- [ ] Every finding includes file path, line number (where applicable), and matched pattern
- [ ] The .gitignore check has verified all required patterns
- [ ] Report language matches the user's conversation language

### Schema Compliance Check (Mandatory Before Saving to .ww-w-ai/)

Before writing to .ww-w-ai/devtools/scan-security/, verify the JSON output:
- [ ] Every "required" field in schema.json is present and non-empty
- [ ] The findings[] array contains every detected item
- [ ] severitySummary counts match the actual finding counts per severity

## Output

Generate the scan report in the user's conversation language.

Output detection results as a Markdown table in this format:

```
===== Security Scan Report =====

| File:Line | Type | Severity | Pattern |
|-----------|------|----------|---------|
| `src/config/db.ts:15` | Hardcoded Secret | CRITICAL | `password = "admin123"` |
| `src/api/users.ts:42` | SQL Injection | CRITICAL | `f"SELECT * FROM users WHERE id = {id}"` |
| `src/components/Post.tsx:18` | XSS | HIGH | `dangerouslySetInnerHTML` |
| `.gitignore` | Unprotected Secret | HIGH | `.env` pattern missing |
| `src/handlers/error.ts:30` | Error Information Exposure | MEDIUM | `str(e)` returned directly |

Total suspected items: {N}
  CRITICAL: {C}
  HIGH: {H}
  MEDIUM: {M}

==============================
```

When there are no suspected items:

```
===== Security Scan Report =====

No suspected items.

==============================
```

## Output Persistence

After generating the security scan report, save results to `.ww-w-ai/devtools/scan-security/`:

1. Create `.ww-w-ai/devtools/scan-security/` if missing
2. Write `latest.json` -- structured result following `templates/schema.json`
3. Write `latest.md` -- human-readable report following `templates/report.template.md`
4. Archive to `history/` -- copy latest.json to `.ww-w-ai/devtools/scan-security/history/{timestamp}.json`

`latest.md` is generated in the user's conversation language. JSON field names stay in English regardless of language.
The JSON output enables machine-parseable history tracking and cross-run comparison.
The history/ directory preserves previous executions for trend analysis.

## Permission Rationale

- **Write**: Exclusively for .ww-w-ai/ output persistence. No project source modification.
- **Bash**: Exclusively for read-only git/system queries. No file modifications.

## Notes

- Bash is permitted for directory creation (`mkdir -p .ww-w-ai/devtools/scan-security/history`). The scan itself is read-only and does not modify project files.
- Based on static pattern matching, so **false positives are possible**. Results are presented as "suspected items"; developers must confirm whether real vulnerabilities exist.
- Environment variable assignments (`os.environ["API_KEY"]`) are not hardcoding and are excluded from detection.
- Security test code (code bearing a `SECURITY` prefix comment) is treated as intentionally vulnerable per security.md exceptions.

## Spec Reference

For detailed validation criteria, evidence tables, and examples:
- Corresponding rule spec: `../../docs/specs/security.md`

