Node.js / JavaScript / TypeScript Security Audit
Overview
This skill answers a very practical question:
"Is this Node.js app safe to run on AWS — and if not, what should I fix?"
It performs a static security audit of Node.js / JavaScript / TypeScript codebases and produces an actionable Markdown report with concrete findings and real, code-level risks that matter in production, especially for Node applications running on AWS.
I built it to be safe, explicit, and predictable in agent-driven workflows, so that you can understand security context before production problems appear.
The problem it solves
Node.js apps often look fine in CI:
- Tests pass
- Builds succeed
- Infrastructure deploys
…and yet security issues quietly slip through.
Common reasons:
- AWS SDKs are easy to misuse
- Secrets leak through environment assumptions
- Risky patterns don't fail loudly
- Agents and scripts run "helpful" but vague shell commands
This skill makes security checks:
- Explicit (no hidden execution)
- Repeatable (same input, same output)
- Reviewable (clear Markdown, not logs)
What it checks
- OWASP Top 10 (2021) mapped to real Node.js vulnerability patterns
- Common AWS security anti-patterns in application code
- Risky handling of secrets, environment variables, and credentials
- Code paths that may enable data exposure or privilege escalation
What you get
An actually readable Markdown report
Clear issue descriptions (no scanner gibberish)
Actionable advice you can follow or task your agent with
Output suitable for:
- Pull requests
- CI artifacts
- Agent context
- Security reviews
Where it fits
- Local development
- CI pipelines
- AWS workloads
- AI agents using Skills.sh as a constrained execution layer
Script security policy
All scripts in scripts/ follow these constraints:
- No network calls — scripts never use curl, wget, fetch, or any network I/O
- No data exfiltration — output is written only to local files in the working directory
- Transparent execution — all actions are printed to stdout as they run
- Minimal privileges — scripts require no elevated permissions; they only read project files and write audit output
- Hardened against scanned-project attacks — NODE_OPTIONS is unset, output paths are checked for symlinks, scanned code output is sanitized to prevent prompt injection
CRITICAL: Execute each workflow step as exactly one bash tool call. Steps must run in sequence — do not launch multiple steps in parallel. Within each step, all shell commands are chained into a single bash invocation (using && / \).
Workflow
Step 1: Discover project structure
Run this single command block to discover the project structure:
echo "=== Package manifests ===" && \
find . -maxdepth 3 -name "package.json" -not -path "*/node_modules/*" 2>/dev/null; \
echo "" && echo "=== Source files ===" && \
find . -type f \( -name "*.js" -o -name "*.ts" -o -name "*.jsx" -o -name "*.tsx" -o -name "*.mjs" -o -name "*.cjs" \) -not -path "*/node_modules/*" -not -path "*/dist/*" -not -path "*/.next/*" -not -path "*/build/*" 2>/dev/null | head -100; \
echo "" && echo "=== Config files ===" && \
find . -maxdepth 1 \( -name ".env*" -o -name "tsconfig.json" -o -name ".eslintrc*" -o -name ".npmrc" \) 2>/dev/null; \
echo "" && echo "=== AWS / Container / IaC markers ===" && \
find . -maxdepth 3 \( -name "serverless.yml" -o -name "serverless.yaml" -o -name "serverless.ts" -o -name "template.yaml" -o -name "template.yml" -o -name "sam.yaml" -o -name "cdk.json" -o -name "Dockerfile" -o -name "docker-compose.yml" -o -name "docker-compose.yaml" \) -not -path "*/node_modules/*" 2>/dev/null; \
find . -maxdepth 3 -name "*.tf" -not -path "*/.terraform/*" -not -path "*/node_modules/*" 2>/dev/null | head -10; \
echo "=== Discovery complete ==="
Large codebases: If the source file listing is truncated (>100 files), focus
the scan on entry points (src/, app/, routes/, handlers/, api/) and
configuration files first. Expand to remaining directories if time allows.
Adaptive priority: If AWS/container/IaC markers are detected above (e.g., serverless.yml,
template.yaml, *.tf, Dockerfile, cdk.json), prioritize the infrastructure and deployment
checks (items 13-17) and flag them as infrastructure-critical in the report.
Step 2: Check Node.js runtime version and vulnerable built-in API usage
Run the runtime version scanner:
bash <skill-path>/scripts/node-version-check.sh
This checks:
- Node.js runtime version against known EOL/CVE data
- Usage of vulnerable built-in APIs (http parser, crypto, child_process, vm, etc.)
- OpenSSL version bundled with the runtime
- Dangerous built-in patterns specific to the detected Node.js version
Read references/version-vulnerabilities.md for the full mapping of Node.js
versions to known CVEs and vulnerable built-in APIs.
Step 3: Run dependency audit
Execute the dependency audit script:
bash <skill-path>/scripts/dependency-audit.sh
This produces dependency-audit-results.txt with known CVEs and outdated packages.
If a step fails: If node or npm is not available, note it as a finding
(the target project may not have dependencies installed). Continue with the
remaining steps — partial results are still valuable. Do not abort the audit.
Step 4: Static code analysis
Read references/vulnerability-catalog.md for the full list of patterns, grep
signatures, and code examples. For each vulnerability category, scan the codebase
using the grep patterns provided.
Scan order (by exploit impact):
Critical path — scan these first:
- Runtime version — use results from Step 2 (EOL version = automatic Critical)
- Injection — SQL/NoSQL/command injection,
eval(), Function(), template literals in queries
- Cryptographic failures — hardcoded secrets, weak algorithms, missing HTTPS enforcement
- Broken access control — missing auth middleware, IDOR patterns, CORS misconfiguration
- Vulnerable built-in APIs — use results from Step 2 (http, crypto, vm, child_process)
- Auth failures — weak JWT config, session mismanagement, no MFA support
- Vulnerable dependencies — use results from Step 3
- SSRF — unvalidated URL fetching, DNS rebinding, internal network access
Secondary — scan after critical path:
- Data integrity — prototype pollution, unsafe deserialization, missing CSP
- Security misconfiguration — debug mode in prod, missing helmet, verbose errors
- Insecure design — mass assignment, missing rate limiting, no input schemas
- Logging failures — no audit logging, sensitive data in logs, missing monitoring
Infrastructure checks (if detected):
- AWS Lambda — event source injection, env var secrets, IAM over-permission, function URL auth bypass, /tmp abuse, credential caching, layer poisoning
- Docker/ECS/Fargate — running as root, --inspect in production, secrets in Dockerfile, missing .dockerignore, SIGTERM handling, ALB/WAF, image scanning
- Terraform IaC — IAM wildcards, function URL auth, plaintext secrets, privileged containers, public IP, debug ports, state file encryption, EOL runtimes (Checkov/tfsec cross-reference)
- CloudFormation/SAM IaC — wildcard IAM, hardcoded secrets, missing VPC/DLQ/concurrency, privileged containers, ECS Exec, public IP, ALB without WAF (cfn-nag/AWS Config cross-reference)
- Serverless Framework — wildcard IAM, per-function roles, missing authorizers, cors: true, hardcoded env secrets, function URL auth, serverless-offline/dotenv risks, deployment bucket encryption
Framework checks (if detected):
- Express/Koa — helmet, CSRF, CORS, body limits, sessions, webpack production config risks (source maps, env leaks, eval devtools)
- NestJS — guards, validation pipes, DTO bypass, TypeORM/Prisma injection, Swagger exposure, WebSocket security, GraphQL depth limiting, exception filter leaks, serialization risks
- Fastify — schema validation bypass, plugin encapsulation, reply.hijack(), TypeBox schema injection, content type parser abuse, @fastify/static traversal
- Bun runtime — Bun.serve() security headers, Bun shell injection, bun:sqlite injection, Bun.file() path traversal, non-cryptographic Bun.hash usage
- AppSync/Amplify — authorization mode misconfiguration, resolver injection, GraphQL introspection, Cognito misconfiguration, API key exposure, AppSync Events security
Quick-reference: critical detection patterns
Use these patterns as a minimum scan baseline. See references/vulnerability-catalog.md for the full catalog.
| Category |
Pattern |
| Hardcoded secrets |
(password|secret|api_key|apiKey|token|JWT_SECRET)\s*[:=]\s*['"][^'"]{4,} |
| eval / Function |
\beval\s*\(|new\s+Function\s*\( |
| Command injection |
exec\(|execSync\(|spawn\( with user input |
| SQL injection |
(query|execute)\s*\(\s*['`].*\+\s*req\. |
| NoSQL injection |
\.find\(\s*\{.*req\.(body|query|params) |
| Weak crypto |
createHash\(\s*['"]md5['"]|createHash\(\s*['"]sha1['"] |
| SSRF |
(axios|fetch|http\.get)\(\s*(req\.|url|href) |
| Prototype pollution |
__proto__|constructor\[|\.prototype\s*= |
Step 5: Generate the report
Read references/report-template.md for the exact output format. Fill in {{agent_tool}} with the
tool you are running in (e.g., "Claude Code", "Cursor", "Cline") and {{model_id}} with your
model identifier (e.g., "claude-sonnet-4-5-20250929"). The report must include:
- Security Score (0-100) calculated using the scoring methodology: start at 100, subtract 15/Critical, 10/High, 5/Medium, 2/Low, +5 bonus if no Critical/High, minimum 0. Display with letter grade (A+ through F) and visual progress bar.
- Findings Dashboard with total count, score, and top finding per severity level with file locations
- Node.js runtime version assessment (Critical if EOL, with specific unpatched CVEs)
- Vulnerable built-in API usage section with affected files
- Framework Security Assessment (Express/Koa/webpack checks if detected)
- Findings sorted by severity, each with: ID, title, severity, OWASP category,
filepath:line location, all affected files listed, vulnerable code snippet, explanation, and remediation code snippet
- Quick Wins section — top 3-5 easiest fixes with biggest score impact and projected score after fixes
- Best practices checklist
- Recommended tools section
- Summary footer repeating the score, top priority, and projected score after Quick Wins
Severity classification:
| Severity |
Criteria |
| Critical |
EOL Node.js runtime, RCE, SQL injection, hardcoded secrets in public repos, auth bypass |
| High |
XSS, CSRF without tokens, SSRF, prototype pollution, weak crypto, vulnerable built-in API usage |
| Medium |
Missing security headers, verbose error messages, no rate limiting, outdated deps with known CVEs |
| Low |
Missing strict mode, console.log with PII, no input length limits, informational findings |
Step 6: Save and present
Save the report as security-audit-report.md and then:
- Output the full markdown report directly in the conversation so the user can
read it without opening a file. Show the complete formatted report, not a summary.
- After the full report, remind the user the file was saved to
security-audit-report.md.
- Ask the user if they would like a PDF version of the report. If they say yes,
generate the PDF using one of these methods (in preference order):
npx md-to-pdf security-audit-report.md (no install needed)
pandoc security-audit-report.md -o security-audit-report.pdf (if pandoc is available)
- If neither works, inform the user and suggest installing one of the tools.
1---2name: node-aws-security-audit3description: Perform comprehensive security audits on Node.js, JavaScript, and TypeScript codebases. Scans source code for OWASP Top 10 vulnerabilities, insecure patterns, dependency risks, and generates a prioritized Markdown audit report with severity levels (Critical, High, Medium, Low), code citations, and remediation guidance. Use when asked to audit, review, scan, or check security of a Node.js/JS/TS project, find vulnerabilities, check for OWASP compliance, or generate a security report. Also triggers on: security review, pentest, vulnerability scan, is my code secure, check for injection, check dependencies. Do NOT trigger for: general code reviews, bugfix assistance, feature development, refactoring, performance optimization, or non-security tasks.4license: MIT5---6
7# Node.js / JavaScript / TypeScript Security Audit
8
9## Overview
10
11This skill answers a very practical question:
12
13"Is this Node.js app safe to run on AWS — and if not, what should I fix?"
14
15It performs a static security audit of Node.js / JavaScript / TypeScript codebases and produces an actionable Markdown report with concrete findings and real, code-level risks that matter in production, especially for Node applications running on AWS.
16
17I built it to be safe, explicit, and predictable in agent-driven workflows, so that you can understand security context *before* production problems appear.
18
19---
20
21## The problem it solves
22
23Node.js apps often look fine in CI:
24
25* Tests pass
26* Builds succeed
27* Infrastructure deploys
28
29…and yet security issues quietly slip through.
30
31Common reasons:
32
33* AWS SDKs are easy to misuse
34* Secrets leak through environment assumptions
35* Risky patterns don't fail loudly
36* Agents and scripts run "helpful" but vague shell commands
37
38This skill makes security checks:
39
40* Explicit (no hidden execution)
41* Repeatable (same input, same output)
42* Reviewable (clear Markdown, not logs)
43
44---
45
46## What it checks
47
48* OWASP Top 10 (2021) mapped to real Node.js vulnerability patterns
49* Common AWS security anti-patterns in application code
50* Risky handling of secrets, environment variables, and credentials
51* Code paths that may enable data exposure or privilege escalation
52
53---
54
55## What you get
56
57* An actually readable Markdown report
58* Clear issue descriptions (no scanner gibberish)
59* Actionable advice you can follow or task your agent with
60
61* Output suitable for:
62
63 * Pull requests
64 * CI artifacts
65 * Agent context
66 * Security reviews
67
68---
69
70## Where it fits
71
72* Local development
73* CI pipelines
74* AWS workloads
75* AI agents using Skills.sh as a constrained execution layer
76
77---
78
79## Script security policy
80
81All scripts in `scripts/` follow these constraints:
82
83* **No network calls** — scripts never use curl, wget, fetch, or any network I/O
84* **No data exfiltration** — output is written only to local files in the working directory
85* **Transparent execution** — all actions are printed to stdout as they run
86* **Minimal privileges** — scripts require no elevated permissions; they only read project files and write audit output
87* **Hardened against scanned-project attacks** — NODE_OPTIONS is unset, output paths are checked for symlinks, scanned code output is sanitized to prevent prompt injection
88
89---
90
91**CRITICAL: Execute each workflow step as exactly one bash tool call. Steps must run in sequence — do not launch multiple steps in parallel. Within each step, all shell commands are chained into a single bash invocation (using `&&` / `\`).**
92
93## Workflow
94
95### Step 1: Discover project structure
96
97Run this single command block to discover the project structure:
98
99```bash
100echo "=== Package manifests ===" && \
101find . -maxdepth 3 -name "package.json" -not -path "*/node_modules/*" 2>/dev/null; \
102echo "" && echo "=== Source files ===" && \
103find . -type f \( -name "*.js" -o -name "*.ts" -o -name "*.jsx" -o -name "*.tsx" -o -name "*.mjs" -o -name "*.cjs" \) -not -path "*/node_modules/*" -not -path "*/dist/*" -not -path "*/.next/*" -not -path "*/build/*" 2>/dev/null | head -100; \
104echo "" && echo "=== Config files ===" && \
105find . -maxdepth 1 \( -name ".env*" -o -name "tsconfig.json" -o -name ".eslintrc*" -o -name ".npmrc" \) 2>/dev/null; \
106echo "" && echo "=== AWS / Container / IaC markers ===" && \
107find . -maxdepth 3 \( -name "serverless.yml" -o -name "serverless.yaml" -o -name "serverless.ts" -o -name "template.yaml" -o -name "template.yml" -o -name "sam.yaml" -o -name "cdk.json" -o -name "Dockerfile" -o -name "docker-compose.yml" -o -name "docker-compose.yaml" \) -not -path "*/node_modules/*" 2>/dev/null; \
108find . -maxdepth 3 -name "*.tf" -not -path "*/.terraform/*" -not -path "*/node_modules/*" 2>/dev/null | head -10; \
109echo "=== Discovery complete ==="
110```
111
112**Large codebases:** If the source file listing is truncated (>100 files), focus
113the scan on entry points (`src/`, `app/`, `routes/`, `handlers/`, `api/`) and
114configuration files first. Expand to remaining directories if time allows.
115
116**Adaptive priority:** If AWS/container/IaC markers are detected above (e.g., `serverless.yml`,
117`template.yaml`, `*.tf`, `Dockerfile`, `cdk.json`), prioritize the infrastructure and deployment
118checks (items 13-17) and flag them as infrastructure-critical in the report.
119
120### Step 2: Check Node.js runtime version and vulnerable built-in API usage
121
122Run the runtime version scanner:
123
124```bash
125bash <skill-path>/scripts/node-version-check.sh
126```
127
128This checks:
129
130* Node.js runtime version against known EOL/CVE data
131* Usage of vulnerable built-in APIs (http parser, crypto, child_process, vm, etc.)
132* OpenSSL version bundled with the runtime
133* Dangerous built-in patterns specific to the detected Node.js version
134
135Read `references/version-vulnerabilities.md` for the full mapping of Node.js
136versions to known CVEs and vulnerable built-in APIs.
137
138### Step 3: Run dependency audit
139
140Execute the dependency audit script:
141
142```bash
143bash <skill-path>/scripts/dependency-audit.sh
144```
145
146This produces `dependency-audit-results.txt` with known CVEs and outdated packages.
147
148**If a step fails:** If `node` or `npm` is not available, note it as a finding
149(the target project may not have dependencies installed). Continue with the
150remaining steps — partial results are still valuable. Do not abort the audit.
151
152### Step 4: Static code analysis
153
154Read `references/vulnerability-catalog.md` for the full list of patterns, grep
155signatures, and code examples. For each vulnerability category, scan the codebase
156using the grep patterns provided.
157
158**Scan order (by exploit impact):**
159
160**Critical path — scan these first:**
161
1621. **Runtime version** — use results from Step 2 (EOL version = automatic Critical)
1632. **Injection** — SQL/NoSQL/command injection, `eval()`, `Function()`, template literals in queries
1643. **Cryptographic failures** — hardcoded secrets, weak algorithms, missing HTTPS enforcement
1654. **Broken access control** — missing auth middleware, IDOR patterns, CORS misconfiguration
1665. **Vulnerable built-in APIs** — use results from Step 2 (http, crypto, vm, child_process)
1676. **Auth failures** — weak JWT config, session mismanagement, no MFA support
1687. **Vulnerable dependencies** — use results from Step 3
1698. **SSRF** — unvalidated URL fetching, DNS rebinding, internal network access
170
171**Secondary — scan after critical path:**
172
1739. **Data integrity** — prototype pollution, unsafe deserialization, missing CSP
17410. **Security misconfiguration** — debug mode in prod, missing helmet, verbose errors
17511. **Insecure design** — mass assignment, missing rate limiting, no input schemas
17612. **Logging failures** — no audit logging, sensitive data in logs, missing monitoring
177
178**Infrastructure checks (if detected):**
179
18013. **AWS Lambda** — event source injection, env var secrets, IAM over-permission, function URL auth bypass, /tmp abuse, credential caching, layer poisoning
18114. **Docker/ECS/Fargate** — running as root, --inspect in production, secrets in Dockerfile, missing .dockerignore, SIGTERM handling, ALB/WAF, image scanning
18215. **Terraform IaC** — IAM wildcards, function URL auth, plaintext secrets, privileged containers, public IP, debug ports, state file encryption, EOL runtimes (Checkov/tfsec cross-reference)
18316. **CloudFormation/SAM IaC** — wildcard IAM, hardcoded secrets, missing VPC/DLQ/concurrency, privileged containers, ECS Exec, public IP, ALB without WAF (cfn-nag/AWS Config cross-reference)
18417. **Serverless Framework** — wildcard IAM, per-function roles, missing authorizers, cors: true, hardcoded env secrets, function URL auth, serverless-offline/dotenv risks, deployment bucket encryption
185
186**Framework checks (if detected):**
187
18818. **Express/Koa** — helmet, CSRF, CORS, body limits, sessions, webpack production config risks (source maps, env leaks, eval devtools)
18919. **NestJS** — guards, validation pipes, DTO bypass, TypeORM/Prisma injection, Swagger exposure, WebSocket security, GraphQL depth limiting, exception filter leaks, serialization risks
19020. **Fastify** — schema validation bypass, plugin encapsulation, reply.hijack(), TypeBox schema injection, content type parser abuse, @fastify/static traversal
19121. **Bun runtime** — Bun.serve() security headers, Bun shell injection, bun:sqlite injection, Bun.file() path traversal, non-cryptographic Bun.hash usage
19222. **AppSync/Amplify** — authorization mode misconfiguration, resolver injection, GraphQL introspection, Cognito misconfiguration, API key exposure, AppSync Events security
193
194**Quick-reference: critical detection patterns**
195
196Use these patterns as a minimum scan baseline. See `references/vulnerability-catalog.md` for the full catalog.
197
198| Category | Pattern |
199|----------|---------|
200| Hardcoded secrets | `(password\|secret\|api_key\|apiKey\|token\|JWT_SECRET)\s*[:=]\s*['"][^'"]{4,}` |
201| eval / Function | `\beval\s*\(\|new\s+Function\s*\(` |
202| Command injection | `exec\(\|execSync\(\|spawn\(` with user input |
203| SQL injection | ``(query\|execute)\s*\(\s*['`].*\+\s*req\.`` |
204| NoSQL injection | `\.find\(\s*\{.*req\.(body\|query\|params)` |
205| Weak crypto | `createHash\(\s*['"]md5['"]\|createHash\(\s*['"]sha1['"]` |
206| SSRF | `(axios\|fetch\|http\.get)\(\s*(req\.\|url\|href)` |
207| Prototype pollution | `__proto__\|constructor\[\|\.prototype\s*=` |
208
209### Step 5: Generate the report
210
211Read `references/report-template.md` for the exact output format. Fill in `{{agent_tool}}` with the
212tool you are running in (e.g., "Claude Code", "Cursor", "Cline") and `{{model_id}}` with your
213model identifier (e.g., "claude-sonnet-4-5-20250929"). The report must include:
214
215* **Security Score (0-100)** calculated using the scoring methodology: start at 100, subtract 15/Critical, 10/High, 5/Medium, 2/Low, +5 bonus if no Critical/High, minimum 0. Display with letter grade (A+ through F) and visual progress bar.
216* **Findings Dashboard** with total count, score, and top finding per severity level with file locations
217* **Node.js runtime version assessment** (Critical if EOL, with specific unpatched CVEs)
218* **Vulnerable built-in API usage** section with affected files
219* **Framework Security Assessment** (Express/Koa/webpack checks if detected)
220* Findings sorted by severity, each with: ID, title, severity, OWASP category, `filepath:line` location, all affected files listed, vulnerable code snippet, explanation, and remediation code snippet
221* **Quick Wins** section — top 3-5 easiest fixes with biggest score impact and projected score after fixes
222* Best practices checklist
223* Recommended tools section
224* **Summary footer** repeating the score, top priority, and projected score after Quick Wins
225
226**Severity classification:**
227
228| Severity | Criteria |
229|----------|----------|
230| Critical | EOL Node.js runtime, RCE, SQL injection, hardcoded secrets in public repos, auth bypass |
231| High | XSS, CSRF without tokens, SSRF, prototype pollution, weak crypto, vulnerable built-in API usage |
232| Medium | Missing security headers, verbose error messages, no rate limiting, outdated deps with known CVEs |
233| Low | Missing strict mode, console.log with PII, no input length limits, informational findings |
234
235### Step 6: Save and present
236
237Save the report as `security-audit-report.md` and then:
238
2391. Output the **full markdown report** directly in the conversation so the user can
240 read it without opening a file. Show the complete formatted report, not a summary.
2412. After the full report, remind the user the file was saved to `security-audit-report.md`.
2423. Ask the user if they would like a **PDF version** of the report. If they say yes,
243 generate the PDF using one of these methods (in preference order):
244 * `npx md-to-pdf security-audit-report.md` (no install needed)
245 * `pandoc security-audit-report.md -o security-audit-report.pdf` (if pandoc is available)
246 * If neither works, inform the user and suggest installing one of the tools.