security-scan
Security Scan Skill
When to use this skill
Activate this skill when asked to:
- Run a security scan or security audit on a project
- Find vulnerabilities, hardcoded secrets, or security misconfigurations
- Check for insecure dependencies (CVEs in npm, NuGet, pip, Maven, etc.)
- Generate a security report for the team or a code review
- Check if external tools like Semgrep, Trivy, or Gitleaks are installed
- Scan a specific category (e.g. "only check for secrets" or "check XSS only")
Quick start
node .github/skills/security-scan/scripts/scan.mjs
With options:
node .github/skills/security-scan/scripts/scan.mjs \
--root /path/to/project \
--categories A,B,C \
--output /path/to/report.html
Parameters
| Parameter | Short | Default | Description |
|---|---|---|---|
--root |
-r |
current directory | Absolute path to the project root |
--categories |
-c |
A,B,C,D,E,F,G,H,I,J,K,L,M |
Comma-separated subset of categories to scan |
--output |
-o |
<root>/security-report.md |
Path for the generated Markdown report |
--json |
false |
Also write findings as JSON to stdout |
Security categories
| Cat | Name | What is detected |
|---|---|---|
| A | Secrets | Hardcoded API keys, passwords, tokens, connection strings in source files and config |
| B | Auth / CSRF | Missing authentication middleware, public endpoints without auth, missing CSRF protection |
| C | XSS | innerHTML, dangerouslySetInnerHTML (React), v-html (Vue), [innerHTML]/bypassSecurityTrust* (Angular), {@html} (Svelte), eval(), document.write() |
| D | SQL Injection | String-concatenated SQL queries, raw query execution with user input |
| E | Business Logic | Bypass parameters, skip-validation flags, forced flow overrides without role checks |
| F | Error Disclosure | Stack traces, exception messages, or internal paths forwarded to the client |
| G | Dependencies / Infra | Known CVEs in npm/NuGet/pip/Maven packages via npm audit / pnpm audit / yarn audit (runs in every package directory — monorepo aware), packages published less than 7 days ago, Docker containers running as root, misconfigurations |
| H | Transport Security | Disabled TLS validation, plain HTTP endpoints in config, insecure cookie flags |
| I | OWASP Top 10 | A02 weak crypto (MD5/SHA-1), A03 command/NoSQL injection, A05 debug-mode config, A07 no rate limiting on auth, A09 no structured logging, A10 SSRF |
| J | Input Validation | No backend validation library, req.body passed directly to DB/ORM, no frontend validation library with forms present, API calls without client-side validation |
| K | Data Privacy / PII | Logging van gevoelige velden (BSN, wachtwoorden), persoonsgegevens in URL parameters, ontbrekende encryptie at rest |
| L | File Uploads | Ontbrekende file-type validatie (MIME), ontbrekende virusscan-stap, te grote bestanden (DoS), onveilige opslagpaden |
| M | IDOR / Logic | Toegang tot intake-gegevens van anderen via een ID in de URL (/api/intake/123), ontbrekende eigenaarschap-checks |
Intake-app specifieke aandachtspunten
Bij intake-applicaties zijn de volgende risico's extra relevant:
1. Mass Assignment (De req.body valkuil)
AI heeft de neiging om lui te programmeren met database-updates. Je ziet dan vaak iets als User.update(req.body).
Het risico: Een kwaadwillende gebruiker kan extra velden meesturen in de JSON (bijvoorbeeld role: 'admin' of status: 'goedgekeurd') die de AI-gegenereerde code dan klakkeloos doorvoert naar de database.
Check: Worden de velden die de database in gaan expliciet gedefinieerd (allow-listing)?
2. IDOR (Insecure Direct Object Reference)
Bij intakes krijgt een gebruiker vaak een overzichtspagina. Als de URL eruitziet als /intake/85, is het eerste wat een tester doet /intake/84 intypen.
Het risico: "Vibe coding" vergeet vaak de check: "Is de ingelogde gebruiker wel de eigenaar van dit intake-ID?".
Check: Controleer in de backend of er bij elk verzoek wordt gecheckt of het object wel bij de gebruiker hoort.
3. File Upload ellende
Als mensen documenten moeten uploaden (ID-bewijs, diploma's), is dat een enorm risico.
Het risico: Iemand uploadt een .html bestand met een script erin, of een executable vermomd als .pdf.
Check: Wordt er alleen op bestandsextensie gecheckt, of ook op de daadwerkelijke "magic bytes" (inhoud) van het bestand? En worden de bestanden hernoemd bij opslag om path traversal te voorkomen?
4. Client-side validatie is geen security
AI bouwt vaak prachtige validatie in React (met mooie roze tekstjes als je een veld vergeet), maar vergeet diezelfde logica soms in de NodeJS backend.
Het risico: Een gebruiker kan met curl of Postman de frontend omzeilen en ongeldige of schadelijke data direct naar je API sturen.
Check: Is er een bibliotheek zoals Joi, Zod of express-validator aanwezig die de API-input echt dwingend valideert?
External tools
The script auto-detects installed tools and uses them if available:
| Tool | Role | Install |
|---|---|---|
| Gitleaks | Secrets in source code and Git history | brew install gitleaks |
| Trivy | CVEs in npm, NuGet, pip, Maven, Docker images | brew install aquasecurity/trivy/trivy |
| Semgrep | OWASP-based static analysis across 20+ languages | brew install semgrep |
If a tool is not installed, the script shows the exact install command and lists what will be missed.
Tip: Install all three tools to get the most complete scan results. Semgrep in particular significantly expands language-specific pattern detection.
Built-in: npm/pnpm/yarn audit (no install required)
Category G always runs npm audit --json, pnpm audit --json, or yarn audit --json in every Node.js package directory found in the project. In a monorepo (e.g. with separate backend/ and frontend/ packages), each sub-package is audited independently. The correct package manager is auto-detected from the lock file present (pnpm-lock.yaml → pnpm, yarn.lock → yarn, otherwise npm). Only packages with an installed node_modules directory are audited.
How to interpret results
- 🔴 Critical — Immediate action required (rotate secrets, fix broken auth pipelines)
- 🟠 High — Address within the current sprint
- 🟡 Medium — Plan in the backlog
- ⚪ Low — Technical debt, address over time
The Markdown report (security-report.md) renders natively in GitHub PRs, VS Code, and any GFM-compatible viewer. Each row contains the finding title, description, file reference, and remediation recommendation.
Output
The scan produces:
- Markdown report (
security-report.md) — GFM table sorted by severity with summary counts, module, category, finding, file reference, and recommendation. Renders natively in GitHub, VS Code, and any Markdown viewer. - Terminal summary — counts per severity + top findings printed to stderr
- JSON output (optional via
--json) — for integration with CI pipelines or other tooling
Typical agent workflow
- Run:
node .github/skills/security-scan/scripts/scan.mjs - Read the terminal summary
- Report to the user: total findings per severity level
- Provide install instructions for any missing external tools
- Point to the generated HTML report for the full findings list
- Highlight the top critical/high findings that need immediate attention