From db31e46b120207def8f27284e831da084566db44 Mon Sep 17 00:00:00 2001 From: Jeremy Meyer Date: Sat, 6 Jun 2026 10:55:08 -0700 Subject: [PATCH] feat(rules): add A10:2021 SSRF detection (#31) - New native rule A10-SSRF for JavaScript/TypeScript and Python - Detects user-controlled URLs in fetch, axios, http/https.get, request - Detects Python requests.get/post and urllib.request.urlopen with Flask input - Fixtures: a10-ssrf.ts (JS), a10-ssrf-vuln.py, a10-ssrf-clean.ts - Tests updated: all 31 tests passing - README updated to reflect A10 coverage (7/10 OWASP categories) Closes #31 Refs #33 --- README.md | 2 +- packages/cli/src/rules/a10-ssrf.ts | 121 +++++++++++++++++++ packages/cli/src/rules/index.ts | 2 + packages/cli/test/fixtures/a10-ssrf-clean.ts | 9 ++ packages/cli/test/fixtures/a10-ssrf-vuln.py | 13 ++ packages/cli/test/fixtures/a10-ssrf.ts | 23 ++++ packages/cli/test/native-rules.test.mjs | 24 ++++ 7 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 packages/cli/src/rules/a10-ssrf.ts create mode 100644 packages/cli/test/fixtures/a10-ssrf-clean.ts create mode 100644 packages/cli/test/fixtures/a10-ssrf-vuln.py create mode 100644 packages/cli/test/fixtures/a10-ssrf.ts diff --git a/README.md b/README.md index 75b40c5..24557e5 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ installed (see `owasp-wtf doctor`): | Layer | Tool | OWASP categories | |-------|------|------------------| -| Native rules (bundled) | regex rules | A01, A02, A03, A05, A07, A09 | +| Native rules (bundled) | regex rules | A01, A02, A03, A05, A07, A09, A10 | | SAST | [Semgrep](https://semgrep.dev) | A01–A05, A07, A08 | | Secrets | [Gitleaks](https://github.com/gitleaks/gitleaks) | A02, A05 | | Dependencies / IaC | [Trivy](https://trivy.dev) | A05, A06, A08 | diff --git a/packages/cli/src/rules/a10-ssrf.ts b/packages/cli/src/rules/a10-ssrf.ts new file mode 100644 index 0000000..d493fcb --- /dev/null +++ b/packages/cli/src/rules/a10-ssrf.ts @@ -0,0 +1,121 @@ +// owasp-wtf-ignore-file — rule definitions, not actual vulnerabilities +import type { Rule, Finding } from '../types.js'; + +function snippet(lines: string[], idx: number): string { + const start = Math.max(0, idx - 2); + const end = Math.min(lines.length - 1, idx + 2); + const result: string[] = []; + for (let i = start; i <= end; i++) { + const marker = i === idx ? '>' : ' '; + result.push(`${marker} ${i + 1} | ${lines[i]}`); + } + return result.join('\n'); +} + +function isComment(line: string): boolean { + const trimmed = line.trim(); + return ( + trimmed.startsWith('//') || + trimmed.startsWith('#') || + trimmed.startsWith('*') || + trimmed.startsWith('/*') || + trimmed.startsWith('