# JavaScript/Node.js Security Audit Guide

> JavaScript/Node.js code security audit module | **Dual-track parallel comprehensive coverage**
> Applicable to: ES5/ES6+, Node.js, TypeScript, Deno

---

## Audit Methodology

### Dual-Track Parallel Framework

```
                  JavaScript/Node.js Code Security Audit
                           |
         +-----------------+-----------------+
         |                 |                 |
         v                 v                 v
+------------------+ +------------------+ +------------------+
| Track A (50%)    | | Track B (40%)    | | Supplement (10%) |
| Control Modeling | | Data Flow Analysis| | Config+Dep Audit |
|                  | |                  | |                  |
| Missing controls:| | Injection vulns: | | • Hardcoded creds|
| • Auth missing   | | • Code injection | | • npm audit     |
| • Authz missing  | | • Prototype poll.| | • CVE deps      |
| • IDOR           | | • Command inj.   | |                 |
| • Race condition | | • Path traversal | |                 |
+------------------+ +------------------+ +------------------+
```

### Dual-Track Core Formulas

```
Track A: Missing class vulns = Sensitive operation - Required control
Track B: Injection class vulns = Source -> [No sanitization] -> Sink
```

**Reference docs**: `references/core/security_controls_methodology.md`, `references/core/data_flow_methodology.md`

---

# Track A: Control Modeling (Missing Class Vulnerabilities)

## A1. Sensitive Operation Enumeration

### 1.1 Quick Identification Commands

```bash
# Express routes - Data modification operations
grep -rn "app\.post\|app\.put\|app\.delete\|app\.patch\|router\.post\|router\.delete" --include="*.js" --include="*.ts"

# NestJS controllers
grep -rn "@Post\|@Put\|@Delete\|@Patch" --include="*.ts"

# Data access operations (with parameters)
grep -rn "app\.get.*:\|router\.get.*:\|@Get.*:" --include="*.js" --include="*.ts"

# Batch operations
grep -rn "export.*=\|download\|batch" --include="*.js" --include="*.ts"

# Financial operations
grep -rn "transfer\|payment\|refund\|balance" --include="*.js" --include="*.ts"

# External HTTP requests
grep -rn "axios\.\|fetch(\|http\.request\|got\(" --include="*.js" --include="*.ts"

# File operations
grep -rn "fs\.readFile\|fs\.writeFile\|fs\.unlink\|multer" --include="*.js" --include="*.ts"

# Command execution
grep -rn "child_process\|exec(\|spawn(\|execSync" --include="*.js" --include="*.ts"
```

### 1.2 Output Template

```markdown
## Node.js Sensitive Operations Checklist

| # | Endpoint/Function | HTTP Method | Sensitive Type | Location | Risk Level |
|---|-------------------|-------------|----------------|----------|------------|
| 1 | /api/user/:id | DELETE | Data modification | userController.js:45 | High |
| 2 | /api/user/:id | GET | Data access | userController.js:32 | Medium |
| 3 | /api/transfer | POST | Financial operation | paymentController.js:56 | Critical |
```

---

## A2. Security Control Modeling

### 2.1 Node.js Security Control Implementation Methods

| Control Type | Express | NestJS | Koa |
|-------------|---------|--------|-----|
| **Authentication** | passport, express-jwt | `@UseGuards(AuthGuard)` | koa-passport |
| **Authorization** | CASL, custom middleware | `@Roles()`, Guards | custom middleware |
| **Resource ownership** | middleware check | Guards | middleware check |
| **Input validation** | express-validator, Joi | class-validator, Pipes | joi, yup |
| **Concurrency control** | Database transactions | TypeORM transactions | Sequelize transactions |
| **Audit logging** | morgan, winston | Interceptors | koa-logger |

### 2.2 Control Matrix Template (Node.js)

```yaml
Sensitive operation: DELETE /api/user/:id
Location: userController.js:45
Type: Data modification

Required controls:
  Authentication control:
    Requirement: Must be logged in
    Express: passport.authenticate() or jwt middleware
    NestJS: @UseGuards(AuthGuard('jwt'))

  Authorization control:
    Requirement: Admin or self
    Express: CASL ability.can() or custom middleware
    NestJS: @Roles('admin') + RolesGuard

  Resource ownership:
    Requirement: Non-admin can only delete own data
    Verification: req.user.id === resource.userId
```

---

## A3. Control Existence Verification

### 3.1 Data Modification Operation Verification Checklist

```markdown
## Control Verification: [Endpoint Name]

| Control Item | Required | Express Implementation | NestJS Implementation | Result |
|-------------|----------|----------------------|----------------------|--------|
| Authentication | Required | passport middleware | @UseGuards | ✅/❌ |
| Authorization | Required | CASL/middleware | @Roles Guard | ✅/❌ |
| Resource ownership | Required | req.user.id comparison | Guard check | ✅/❌ |
| Input validation | Required | express-validator | ValidationPipe | ✅/❌ |

### Verification commands
```bash
# Check route middleware
grep -B 5 "router\.delete\|app\.delete" [route file] | grep "authenticate|isAuth|jwt"

# Check resource ownership
grep -A 15 "delete.*async" [controller file] | grep "userId|ownerId|req\.user"
```
```

### 3.2 Common Missing Patterns -> Vulnerability Mapping

| Missing Control | Vulnerability Type | CWE | Node.js Detection Method |
|-----------------|-------------------|-----|-------------------------|
| No jwt middleware | Missing authentication | CWE-306 | Check route middleware chain |
| No CASL/Guards | Missing authorization | CWE-862 | Check ability checks |
| No userId comparison | IDOR | CWE-639 | Check query conditions |
| No transaction lock | Race condition | CWE-362 | Check financial operations |

---

# Track B: Data Flow Analysis (Injection Class Vulnerabilities)

> **Core formula**: Source -> [No sanitization] -> Sink = Injection class vulnerability

## B1. Node.js Source

```javascript
// Express
req.query.name        // GET parameters
req.body.name         // POST body
req.params.id         // Path parameters
req.headers['x-header']
req.cookies.session
req.files             // File upload
```

## B2. Node.js Sink

| Sink Type | Vulnerability | CWE | Dangerous Functions |
|-----------|--------------|-----|---------------------|
| Code execution | Code injection | 94 | eval, Function, vm.run |
| Command execution | Command injection | 78 | child_process.exec |
| SQL execution | SQL injection | 89 | connection.query |
| File operations | Path traversal | 22 | fs.readFile, fs.writeFile |
| Prototype pollution | Prototype pollution | 1321 | Object.assign, _.merge |

## B3. Sink Detection Commands

## Core Attack Surface

JavaScript's dynamic nature, prototype chain mechanism, and asynchronous programming model bring unique security challenges. Key attack surfaces: code injection, prototype pollution, ReDoS, path traversal, insecure deserialization.

---

## Supplementary Detection Commands (grep-driven)

### Code Injection Detection

```javascript
// High-risk function list
eval(code)                           // Execute arbitrary code
Function(code)()                     // Dynamic function construction
setTimeout(code_string, delay)       // String timeout callback
setInterval(code_string, delay)      // String interval callback
new Function('return ' + code)()     // Constructor injection
vm.runInNewContext(code)             // VM module execution
vm.runInThisContext(code)            // Current context execution
require('child_process').exec(cmd)   // Command execution

// Audit regex
\beval\s*\(|\bFunction\s*\(|setTimeout\s*\([^,)]*?[\+\`]|setInterval\s*\([^,)]*?[\+\`]
vm\.run|child_process|exec\s*\(|spawn\s*\(

// Vulnerability example
const userCode = req.query.code;
eval(userCode);  // ❌ Critical: Arbitrary code execution

// Safe alternative
const vm = require('vm');
const sandbox = Object.create(null);
vm.runInNewContext(code, sandbox, { timeout: 1000 });  // Limited sandbox
```

---

## Prototype Pollution Detection

```javascript
// Prototype pollution vectors
Object.assign(target, source)        // Recursive object merge
_.merge(target, source)              // Lodash merge
_.mergeWith(target, source)          // Custom merge
$.extend(true, target, source)       // jQuery deep copy
hoek.merge(target, source)           // Hoek merge

// Dangerous properties
__proto__
constructor.prototype
prototype

// Audit regex
(Object\.assign|_\.merge|_\.set|_\.defaults|\$\.extend)\s*\(
__proto__|constructor\.prototype

// Vulnerability example
function merge(target, source) {
    for (let key in source) {
        if (typeof source[key] === 'object') {
            target[key] = merge(target[key] || {}, source[key]);
        } else {
            target[key] = source[key];  // ❌ High: Prototype pollution
        }
    }
    return target;
}

// Attack payload
POST /api/merge
{
  "__proto__": {
    "isAdmin": true,
    "role": "admin"
  }
}

// Safe measures
function safeMerge(target, source) {
    for (let key in source) {
        if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
            continue;  // ✓ Filter dangerous properties
        }
        if (Object.prototype.hasOwnProperty.call(source, key)) {
            target[key] = source[key];
        }
    }
}

// Use Object.create(null) to create objects without prototype
const safeObj = Object.create(null);
```

---

## Command Injection Detection

```javascript
// High-risk modules and functions
child_process.exec(cmd)              // Shell execution
child_process.execSync(cmd)          // Synchronous shell execution
child_process.spawn(cmd, {shell:true}) // Dangerous when shell=true
child_process.execFile(file, args)   // File execution
require('shelljs').exec(cmd)         // ShellJS

// Audit regex
child_process\.(exec|spawn|execSync|execFile|fork)
shelljs.*exec|sh\.exec

// Vulnerability example
const { exec } = require('child_process');
const filename = req.query.file;
exec(`cat ${filename}`, (err, stdout) => {  // ❌ Critical
    res.send(stdout);
});

// Attack payload
GET /api/file?file=test.txt;id;whoami

// Safe alternative
const { execFile } = require('child_process');
execFile('cat', [filename], (err, stdout) => {  // ✓ Use argument array
    res.send(stdout);
});

// Or use spawn without shell
const { spawn } = require('child_process');
const child = spawn('cat', [filename]);  // ✓ shell=false (default)
```

---

## Path Traversal Detection

```javascript
// Dangerous operations
fs.readFile(userPath)                // File read
fs.writeFile(userPath)               // File write
fs.createReadStream(userPath)        // Stream read
require(userModule)                  // Dynamic module loading
res.sendFile(userPath)               // Express send file
res.download(userPath)               // Express download

// Audit regex
fs\.(readFile|writeFile|readFileSync|createReadStream|createWriteStream|unlink)
res\.(sendFile|download)\s*\(|require\s*\(.*?req\.(query|body|params)

// Vulnerability example
app.get('/download', (req, res) => {
    const file = req.query.file;
    res.sendFile(__dirname + '/files/' + file);  // ❌ High: Path traversal
});

// Attack payload
GET /download?file=../../../etc/passwd

// Safe fix
const path = require('path');
const file = req.query.file;
const safePath = path.normalize(file).replace(/^(\.\.(\/|\\|$))+/, '');
const fullPath = path.join(__dirname, 'files', safePath);

if (!fullPath.startsWith(path.join(__dirname, 'files'))) {
    return res.status(403).send('Forbidden');
}
res.sendFile(fullPath);  // ✓
```

---

## Regular Expression Denial of Service (ReDoS)

```javascript
// Dangerous regex patterns
(a+)+                                // Nested quantifiers
(a|a)*                               // Repeated alternation
(a|ab)*                              // Overlapping alternation
(\w+\s?)*                            // Character class+space quantifier

// Audit regex
/\([^)]*[\+\*]\)\+/                  // Detect nested quantifiers

// Vulnerability example
const emailRegex = /^([a-zA-Z0-9]+)+@[a-zA-Z0-9]+\.[a-zA-Z]{2,}$/;
if (emailRegex.test(userInput)) {    // ❌ Medium: ReDoS
    // ...
}

// Attack payload
"aaaaaaaaaaaaaaaaaaaaaaaaaaaa!"  // No match but causes exponential backtracking

// Safe fix
const emailRegex = /^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z]{2,}$/;  // ✓ Remove nested quantifiers

// Use safe-regex for detection
const safe = require('safe-regex');
if (!safe(regex)) {
    console.warn('Unsafe regex detected!');
}
```

---

## JSON Injection and Deserialization

```javascript
// Insecure deserialization
JSON.parse(userInput)                // Usually safe, but beware of prototype pollution
eval('(' + jsonString + ')')         // ❌ Extremely dangerous
node-serialize.unserialize()         // Can execute code
cryo.parse()                         // Can restore functions

// Audit regex
eval\s*\(.*JSON|serialize\.unserialize|cryo\.(parse|hydrate)

// Vulnerability example - node-serialize
const serialize = require('node-serialize');
const userCookie = req.cookies.profile;
const obj = serialize.unserialize(userCookie);  // ❌ Critical

// Attack payload
{"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('calc')}()"}

// Safe measures
const data = JSON.parse(userInput);  // ✓ Only use JSON.parse
// Validate deserialized object structure
if (!isValidUser(data)) {
    throw new Error('Invalid data structure');
}
```

---

## XSS Detection (Server-Side Rendering)

```javascript
// Dangerous template engine configuration
// EJS
<%= userInput %>                     // ❌ Unescaped output
<%- userInput %>                     // ❌ Raw HTML

// Pug/Jade
!= userInput                         // ❌ Unescaped
div!= userInput                      // ❌ Unescaped

// Handlebars
{{{ userInput }}}                    // ❌ Triple curly braces unescaped

// Audit keywords
res.send|res.write|innerHTML|dangerouslySetInnerHTML
<%=|<%-|!{|{{{{

// Vulnerability example
app.get('/greet', (req, res) => {
    const name = req.query.name;
    res.send(`<h1>Hello ${name}</h1>`);  // ❌ High: XSS
});

// Safe fix
const escapeHtml = require('escape-html');
res.send(`<h1>Hello ${escapeHtml(name)}</h1>`);  // ✓

// React/Vue components
<div dangerouslySetInnerHTML={{__html: userInput}} />  // ❌ High
<div v-html="userInput"></div>                          // ❌ High
```

---

## SQL Injection Detection (Node.js ORM)

```javascript
// Dangerous operations
// Sequelize
User.findAll({ where: sequelize.literal(userInput) })  // ❌
sequelize.query(`SELECT * FROM users WHERE id=${id}`)  // ❌

// Knex
knex.raw(`SELECT * FROM users WHERE name='${name}'`)   // ❌

// TypeORM
manager.query(`SELECT * FROM users WHERE id=${id}`)    // ❌

// Audit regex
sequelize\.(literal|query)|knex\.raw|manager\.query.*\$\{

// Vulnerability example
app.get('/users', async (req, res) => {
    const id = req.query.id;
    const query = `SELECT * FROM users WHERE id = ${id}`;
    const users = await sequelize.query(query);  // ❌ Critical
    res.json(users);
});

// Safe fix
const users = await sequelize.query(
    'SELECT * FROM users WHERE id = ?',
    { replacements: [id], type: QueryTypes.SELECT }  // ✓ Parameterized query
);

// ORM safe approach
const user = await User.findByPk(id);  // ✓
const users = await User.findAll({ where: { status: userStatus } });  // ✓
```

---

## NoSQL Injection Detection (MongoDB)

```javascript
// Dangerous operations
db.collection.find(JSON.parse(userInput))         // ❌
db.collection.find({ $where: userCondition })     // ❌
User.find(req.query)                              // ❌ Mongoose direct query pass

// Audit regex
\$where|JSON\.parse.*req\.(query|body)|\.find\(req\.(query|body)\)

// Vulnerability example
app.get('/users', async (req, res) => {
    const filter = req.query;
    const users = await User.find(filter);  // ❌ High: NoSQL injection
    res.json(users);
});

// Attack payload
GET /users?username[$ne]=null&password[$ne]=null  // Bypass authentication
GET /users?$where=this.password.length<20         // $where injection

// Safe fix
const { username } = req.query;
if (typeof username !== 'string') {
    return res.status(400).send('Invalid input');
}
const users = await User.find({ username: username });  // ✓ Explicit field

// Use whitelist
const allowedFields = ['username', 'email', 'status'];
const filter = {};
for (let key in req.query) {
    if (allowedFields.includes(key) && typeof req.query[key] === 'string') {
        filter[key] = req.query[key];
    }
}
```

---

## SSRF Detection

```javascript
// Dangerous functions
http.get(url)                        // HTTP request
https.request(url)                   // HTTPS request
axios.get(url)                       // Axios
fetch(url)                           // Fetch API
request(url)                         // Request library
got(url)                             // Got library

// Audit regex
(http|https|axios|fetch|request|got)\.(get|post|request)\s*\(.*?req\.(query|body|params)

// Vulnerability example
app.get('/fetch', async (req, res) => {
    const url = req.query.url;
    const response = await axios.get(url);  // ❌ High: SSRF
    res.send(response.data);
});

// Attack payload
GET /fetch?url=http://169.254.169.254/latest/meta-data/  // AWS metadata
GET /fetch?url=http://localhost:6379/                    // Internal Redis
GET /fetch?url=file:///etc/passwd                        // File read

// Safe fix
const url = require('url');
const targetUrl = req.query.url;
const parsed = new URL(targetUrl);

// Blacklist check
const blockedHosts = ['169.254.169.254', 'localhost', '127.0.0.1', '0.0.0.0'];
const blockedSchemes = ['file', 'gopher', 'dict'];

if (blockedSchemes.includes(parsed.protocol.replace(':', ''))) {
    return res.status(403).send('Forbidden protocol');
}

if (blockedHosts.includes(parsed.hostname)) {
    return res.status(403).send('Forbidden host');
}

// Whitelist is more secure
const allowedHosts = ['api.example.com', 'cdn.example.com'];
if (!allowedHosts.includes(parsed.hostname)) {
    return res.status(403).send('Unauthorized host');
}
```

---

## JWT Security Detection

```javascript
// Common vulnerabilities
jwt.verify(token, secret, { algorithms: ['HS256', 'none'] })  // ❌ Allows none algorithm
jwt.decode(token)                                              // ❌ No signature verification
jwt.sign(payload, null)                                        // ❌ Empty secret

// Audit regex
jwt\.decode\s*\((?!.*verify)|algorithms.*none|jwt\.sign.*null

// Vulnerability example
app.get('/admin', (req, res) => {
    const token = req.headers.authorization;
    const decoded = jwt.decode(token);  // ❌ High: No signature verification
    if (decoded.role === 'admin') {
        res.send('Admin panel');
    }
});

// Attack payload - none algorithm bypass
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJyb2xlIjoiYWRtaW4ifQ.

// Safe fix
const secret = process.env.JWT_SECRET;
try {
    const decoded = jwt.verify(token, secret, {
        algorithms: ['HS256']  // ✓ Explicitly specify algorithm
    });
    if (decoded.role === 'admin') {
        res.send('Admin panel');
    }
} catch (err) {
    res.status(401).send('Invalid token');
}

// Secret key security
// ❌ Hardcoded key
const SECRET = 'my-secret-key-123';

// ✓ Environment variable + strong key
const SECRET = process.env.JWT_SECRET;  // At least 32 bytes random
```

---

## Open Redirect Detection

```javascript
// Dangerous operations
res.redirect(req.query.url)          // ❌ Direct redirect
res.redirect(301, req.body.next)     // ❌ User-controlled target

// Audit regex
res\.redirect\s*\(.*?req\.(query|body|params)

// Vulnerability example
app.get('/logout', (req, res) => {
    const returnUrl = req.query.return;
    res.clearCookie('session');
    res.redirect(returnUrl);  // ❌ Medium: Open redirect
});

// Attack payload
GET /logout?return=https://evil.com/phishing

// Safe fix
const allowedDomains = ['example.com', 'app.example.com'];
const url = new URL(returnUrl, 'http://example.com');

if (!allowedDomains.includes(url.hostname)) {
    return res.redirect('/');  // Default safe path
}
res.redirect(returnUrl);

// Or only allow relative paths
if (returnUrl.startsWith('/') && !returnUrl.startsWith('//')) {
    res.redirect(returnUrl);  // ✓
}
```

---

## Race Condition Detection

```javascript
// TOCTOU (Time-of-check to Time-of-use)
if (await canWithdraw(user, amount)) {  // Check
    await withdraw(user, amount);        // Use - ❌ Race window
}

// Vulnerability example - Balance check
async function transfer(from, to, amount) {
    const balance = await getBalance(from);
    if (balance >= amount) {            // ❌ Race condition
        await deduct(from, amount);
        await credit(to, amount);
    }
}

// Attack scenario: Send multiple transfer requests simultaneously

// Safe fix - Atomic operations
async function transfer(from, to, amount) {
    const session = await db.startSession();
    session.startTransaction();
    try {
        await Account.updateOne(
            { _id: from, balance: { $gte: amount } },
            { $inc: { balance: -amount } },
            { session }
        );  // ✓ Atomic update
        await Account.updateOne(
            { _id: to },
            { $inc: { balance: amount } },
            { session }
        );
        await session.commitTransaction();
    } catch (err) {
        await session.abortTransaction();
        throw err;
    } finally {
        session.endSession();
    }
}

// Redis distributed lock
const Redlock = require('redlock');
const lock = await redlock.lock('transfer:' + userId, 1000);
try {
    // Execute transfer
} finally {
    await lock.unlock();
}
```

---

## Sensitive Information Leak Detection

```javascript
// Dangerous patterns
console.log(req.body.password)       // Log leaks password
console.error(err.stack)             // Detailed stack trace
res.send(err)                        // Error object returned directly
process.env                          // Environment variable leak

// Audit regex
console\.(log|error|info).*password|res\.(send|json)\(err\)|JSON\.stringify\(process\.env\)
app\.use\(express\.errorHandler\(\)\)

// Vulnerability example
app.post('/login', async (req, res) => {
    try {
        const user = await authenticate(req.body);
        console.log('Login:', req.body);  // ❌ Low: Password logged
        res.json({ token: user.token });
    } catch (err) {
        res.status(500).json({ error: err.stack });  // ❌ Medium: Stack trace leak
    }
});

// Safe fix
const sanitized = { ...req.body };
delete sanitized.password;
logger.info('Login attempt', sanitized);  // ✓

// Unified error handling
app.use((err, req, res, next) => {
    logger.error(err);  // Backend logs full error
    res.status(500).json({
        error: process.env.NODE_ENV === 'production'
            ? 'Internal server error'  // ✓ Hide details in production
            : err.message
    });
});
```

---

## package.json Dependency Audit

```bash
# Check known vulnerabilities
npm audit
yarn audit

# Common vulnerable dependencies
lodash < 4.17.21                     # Prototype pollution
minimist < 1.2.6                     # Prototype pollution
node-serialize                       # RCE
js-yaml < 3.13.1                     # Code execution
handlebars < 4.7.7                   # RCE
express < 4.17.3                     # Open redirect
jsonwebtoken < 9.0.0                 # Algorithm confusion

# Audit regex (in package.json)
"lodash":\s*"[<^~]?[0-3]\.|"^4\.(0|1[0-6])\."
"minimist":\s*"[<^~]?[01]\."
```

---

## TypeScript Specific Security

```typescript
// Type assertion bypass
const userInput = req.query.data as string;  // ❌ Unsafe, may not be string
executeQuery(userInput);

// Safe validation
function isString(value: unknown): value is string {
    return typeof value === 'string';
}

if (isString(req.query.data)) {
    executeQuery(req.query.data);  // ✓ Type guard
}

// any type abuse
function process(data: any) {  // ❌ Bypasses type checking
    eval(data.code);
}

// Use unknown instead
function process(data: unknown) {
    if (typeof data === 'object' && data !== null && 'code' in data) {
        // Runtime validation
    }
}
```

---

## Environment Variables and Key Management

```javascript
// Dangerous configuration
const config = {
    dbPassword: 'hardcoded123',      // ❌ Hardcoded password
    apiKey: 'sk-1234567890',         // ❌ Hardcoded API key
    jwtSecret: 'secret'              // ❌ Weak secret
};

// .env file exposure
app.use(express.static('public'));   // ❌ If public contains .env

// Audit regex
password\s*[:=]\s*['"][^'"]+['"]|api[_-]?key\s*[:=]\s*['"]
git add \.env

// Safe measures
// .env file
DB_PASSWORD=use_strong_random_password
JWT_SECRET=at_least_32_bytes_random_string

// .gitignore
.env
.env.local
config/secrets.js

// In code
require('dotenv').config();
const dbPassword = process.env.DB_PASSWORD;

// Validate environment variables
const requiredEnvVars = ['DB_PASSWORD', 'JWT_SECRET', 'API_KEY'];
for (const varName of requiredEnvVars) {
    if (!process.env[varName]) {
        throw new Error(`Missing required env var: ${varName}`);
    }
}
```

---

## Search Pattern Summary

```regex
# Code injection
\beval\s*\(|\bFunction\s*\(|vm\.run.*context|setTimeout.*[\+\`]

# Command injection
child_process\.(exec|spawn).*shell.*true|exec\s*\(.*\$\{

# Prototype pollution
__proto__|constructor\.prototype|Object\.assign|_\.merge

# SQL injection
sequelize\.(literal|query).*\$\{|knex\.raw.*\$\{|\.query\(.*\+

# NoSQL injection
\$where|\.find\(req\.(query|body)\)|JSON\.parse.*req\.

# SSRF
(axios|fetch|http|https|request|got)\.(get|post).*req\.

# Path traversal
res\.(sendFile|download).*req\.|fs\.read.*\+.*req\.|require\(.*req\.

# XSS
res\.send.*\$\{|dangerouslySetInnerHTML|v-html=|<%=.*req\.

# JWT
jwt\.decode\((?!.*verify)|algorithms.*none

# Sensitive information
console\.log.*password|res\.(send|json)\(err\)|\.stack

# Hardcoded secrets
password\s*[:=]\s*['"]|api[_-]?key\s*[:=]\s*['"]|secret.*=.*['"][^'"]{8,}
```

---

## Quick Audit Checklist

```markdown
[ ] Check package.json for known CVEs (npm audit)
[ ] Search eval/Function/vm.run (code injection)
[ ] Search child_process.exec (command injection)
[ ] Search __proto__/Object.assign (prototype pollution)
[ ] Check JWT verification logic (algorithm, secret)
[ ] Check file operation path concatenation (path traversal)
[ ] Check HTTP request functions (SSRF)
[ ] Check database query string concatenation (injection)
[ ] Check template engine unescaped output (XSS)
[ ] Check redirect target source (open redirect)
[ ] Check if .env file is in .gitignore
[ ] Check if error handling leaks stack traces
[ ] Check regular expressions for ReDoS
[ ] Check race conditions (balance, inventory, etc.)
```

---

## Minimal PoC Examples
```bash
# Prototype Pollution
node -e "const a={}; const b=JSON.parse('{\"__proto__\":{\"polluted\":true}}'); Object.assign(a,b); console.log({}.polluted)"

# SSRF
curl "http://localhost:3000/fetch?url=http://169.254.169.254/latest/meta-data/"

# Path traversal
curl "http://localhost:3000/download?file=../../etc/passwd"
```

---

---

## Authorization Vulnerability Detection (Authorization Gap) - v1.7.1

> **Core problem**: Authorization vulnerabilities are "missing code" - grep cannot detect code that "should be there but isn't"
> **Solution**: Authorization matrix approach - start from "what should be" rather than "what exists"

### Methodology

```
❌ Old approach (passive detection - limited):
   Search middleware calls → Check if they exist
   Problem: Existing middleware doesn't mean correct, may be misconfigured or incomplete

✅ New approach (active modeling - systematic):
   1. Enumerate all sensitive operations (DELETE/PUT handlers)
   2. Define expected permissions (who can do what)
   3. Compare with actual code, detect missing or inconsistent controls
```

### Express Authorization Detection

```bash
# Step 1: Find all sensitive routes
grep -rn "\.delete\|\.put\|\.patch" --include="*.js" --include="*.ts"
grep -rn "router\.\(delete\|put\|patch\)" --include="*.js" --include="*.ts"

# Step 2: Check if routes have auth middleware
grep -rn "router\.delete" --include="*.js" -B 2 -A 2 | grep -E "isAuthenticated|requireAuth|passport\.authenticate|verifyToken"

# Step 3: Check if handlers have permission checks
grep -rn "async.*delete\|function.*delete" --include="*.js" -A 20 | grep -E "userId|ownerId|req\.user\.\|checkPermission"
```

### Vulnerability Patterns

```javascript
// ❌ Vulnerability: delete route missing auth middleware
router.delete('/files/:id', async (req, res) => {
    // No user login status check
    await File.findByIdAndDelete(req.params.id);
    res.json({ success: true });
});

// ❌ Vulnerability: Auth present but no authorization (horizontal privilege escalation)
router.delete('/files/:id', isAuthenticated, async (req, res) => {
    // Only verifies login, not file ownership
    await File.findByIdAndDelete(req.params.id);  // Can delete others' files!
    res.json({ success: true });
});

// ✅ Safe: Authentication + Authorization + Resource ownership verification
router.delete('/files/:id', isAuthenticated, async (req, res) => {
    const file = await File.findOne({
        _id: req.params.id,
        owner: req.user._id  // Verify resource ownership
    });

    if (!file) {
        return res.status(403).json({ error: 'Not authorized' });
    }

    await file.remove();
    res.json({ success: true });
});
```

### NestJS Authorization Detection

```bash
# Check Controller Guard configuration
grep -rn "@Delete\|@Put\|@Patch" --include="*.ts" -B 5 | grep -E "@UseGuards|@Roles|AuthGuard"

# Check global Guard configuration
grep -rn "APP_GUARD\|useGlobalGuards" --include="*.ts"
```

### Vulnerability Patterns (NestJS)

```typescript
// ❌ Vulnerability: Controller missing Guard
@Controller('files')
export class FileController {
    @Delete(':id')
    async delete(@Param('id') id: string) {
        // Anyone can access
        return this.fileService.delete(id);
    }
}

// ❌ Vulnerability: Has AuthGuard but no resource ownership verification
@Controller('files')
@UseGuards(AuthGuard('jwt'))
export class FileController {
    @Delete(':id')
    async delete(@Param('id') id: string, @Request() req) {
        // No ownership verification
        return this.fileService.delete(id);
    }
}

// ✅ Safe: AuthGuard + Resource ownership verification
@Controller('files')
@UseGuards(AuthGuard('jwt'))
export class FileController {
    @Delete(':id')
    async delete(@Param('id') id: string, @Request() req) {
        const file = await this.fileService.findOne({
            _id: id,
            owner: req.user.id
        });
        if (!file) {
            throw new ForbiddenException('Not authorized');
        }
        return this.fileService.delete(id);
    }
}
```

### Koa Authorization Detection

```bash
# Check route definitions
grep -rn "router\.delete\|router\.put\|router\.patch" --include="*.js"

# Check middleware
grep -rn "router\.use\|app\.use" --include="*.js" -A 2 | grep -E "auth\|jwt\|session"
```

### Authorization Consistency Detection Script

```bash
#!/bin/bash
# check_auth_consistency_js.sh

echo "=== JavaScript Authorization Consistency Detection ==="

# Find all route files
ROUTE_FILES=$(find . -name "*.js" -o -name "*.ts" | xargs grep -l "router\.\|@Delete\|@Put" 2>/dev/null)

for routefile in $ROUTE_FILES; do
    echo ""
    echo "Checking: $routefile"

    # Express style detection
    DELETE_ROUTES=$(grep -n "\.delete\s*(" "$routefile" 2>/dev/null)
    PUT_ROUTES=$(grep -n "\.put\s*(" "$routefile" 2>/dev/null)

    if [ -n "$DELETE_ROUTES" ]; then
        echo "$DELETE_ROUTES" | while read line; do
            line_num=$(echo "$line" | cut -d: -f1)
            route=$(echo "$line" | cut -d: -f2-)

            # Check for auth middleware
            has_auth=$(echo "$route" | grep -c "isAuthenticated\|requireAuth\|verifyToken\|passport")

            if [ "$has_auth" -eq 0 ]; then
                echo "  ⚠️  Line ${line_num}: DELETE route may be missing auth middleware"
                echo "      $route"
            else
                echo "  ✅ Line ${line_num}: DELETE route has auth check"
            fi
        done
    fi

    # NestJS style detection
    NEST_DELETES=$(grep -n "@Delete" "$routefile" 2>/dev/null)
    if [ -n "$NEST_DELETES" ]; then
        echo "$NEST_DELETES" | while read line; do
            line_num=$(echo "$line" | cut -d: -f1)

            # Check 10 lines above for Guard
            start=$((line_num - 10))
            [ $start -lt 1 ] && start=1

            has_guard=$(sed -n "${start},${line_num}p" "$routefile" | grep -c "@UseGuards\|@Roles")

            if [ "$has_guard" -eq 0 ]; then
                echo "  ⚠️  Line ${line_num}: @Delete may be missing @UseGuards"
            else
                echo "  ✅ Line ${line_num}: @Delete has Guard protection"
            fi
        done
    fi
done
```

### Indirect SSRF Detection (Configuration-Driven)

```javascript
// ❌ Vulnerability: Configuration-driven indirect SSRF
// config.js
const config = {
    apiBaseUrl: process.env.API_URL || 'http://internal-api'
};

// service.js
async function fetchData(endpoint) {
    const url = config.apiBaseUrl + endpoint;  // Indirect SSRF
    return axios.get(url);
}

// Detection commands
grep -rn "process\.env\.\w*URL\|process\.env\.\w*HOST" --include="*.js" --include="*.ts"
grep -rn "config\.\w*[Uu]rl\|config\.\w*[Hh]ost" --include="*.js" --include="*.ts"
grep -rn "\`.*\${.*}.*http\|\`http.*\${" --include="*.js" --include="*.ts"
```

### Audit Checklist (Authorization Focused)

```
Authorization matrix modeling:
- [ ] List all sensitive routes (DELETE/PUT/PATCH)
- [ ] Define expected permissions for each route
- [ ] Check actual middleware configuration matches expectations

Express specific:
- [ ] Check if sensitive routes have auth middleware
- [ ] Verify resource ownership check on DELETE routes
- [ ] Check app.use() global middleware configuration order

NestJS specific:
- [ ] Check Controller-level @UseGuards
- [ ] Check method-level @Roles/@Permissions
- [ ] Verify Guard resource ownership logic

Horizontal privilege escalation prevention:
- [ ] Verify all resource operations check owner/userId
- [ ] Check if database queries include user filter conditions
- [ ] Verify permission checks for batch operations (e.g., batch delete)

Middleware configuration:
- [ ] Check middleware order (authentication -> authorization -> routes)
- [ ] Verify JWT secret strength
- [ ] Check CORS configuration

Indirect injection:
- [ ] Check URL configuration in process.env
- [ ] Trace controllable values in config objects
- [ ] Verify template-string-constructed URLs
```

---

## CSRF Security (CWE-352)

### Dangerous Patterns

```javascript
// Express - CSRF protection not enabled
const app = express();
app.use(express.json());
// 🔴 Missing csrf middleware

app.post('/api/transfer', (req, res) => {
    // State-changing operation without CSRF protection
    transferMoney(req.body.to, req.body.amount);
});
```

### Safe Configuration

```javascript
// Express + csurf
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });

app.use(cookieParser());
app.use(csrfProtection);

app.get('/form', (req, res) => {
    res.render('form', { csrfToken: req.csrfToken() });
});

app.post('/api/transfer', csrfProtection, (req, res) => {
    // CSRF token automatically verified
    transferMoney(req.body.to, req.body.amount);
});

// NestJS
import { CsrfModule } from '@tekuconcept/nestjs-csrf';
@Module({
    imports: [CsrfModule.forRoot({ cookie: true })],
})
export class AppModule {}
```

### Detection Commands

```bash
# Find POST/PUT/DELETE routes without CSRF
rg -n "app\.(post|put|delete|patch)\(" --glob "*.{js,ts}" | grep -v "csrf\|CSRF"

# Find sensitive operations
rg -n "transfer|delete|update|create" --glob "*.{js,ts}" | grep "app\.\|router\."
```

---

## File Upload Security (CWE-434)

### Dangerous Patterns

```javascript
// 🔴 No type validation
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });

app.post('/upload', upload.single('file'), (req, res) => {
    res.json({ filename: req.file.filename });  // Arbitrary file type
});

// 🔴 Frontend validation only
// <input type="file" accept=".jpg,.png">  // Bypassable
```

### Safe Configuration

```javascript
const multer = require('multer');
const path = require('path');

const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif'];
const MAX_SIZE = 5 * 1024 * 1024;  // 5MB

const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, '/uploads/');
    },
    filename: (req, file, cb) => {
        // Generate safe filename
        const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
        const ext = path.extname(file.originalname).toLowerCase();
        if (!['.jpg', '.jpeg', '.png', '.gif'].includes(ext)) {
            return cb(new Error('Invalid extension'));
        }
        cb(null, uniqueSuffix + ext);
    }
});

const fileFilter = (req, file, cb) => {
    if (!ALLOWED_TYPES.includes(file.mimetype)) {
        return cb(new Error('Invalid file type'), false);
    }
    cb(null, true);
};

const upload = multer({
    storage: storage,
    fileFilter: fileFilter,
    limits: { fileSize: MAX_SIZE }
});

app.post('/upload', upload.single('file'), (req, res) => {
    // Additional: Use file-type library to verify actual content
    const FileType = require('file-type');
    const type = await FileType.fromFile(req.file.path);
    if (!type || !ALLOWED_TYPES.includes(type.mime)) {
        fs.unlinkSync(req.file.path);
        return res.status(400).json({ error: 'Invalid file content' });
    }
    res.json({ filename: req.file.filename });
});
```

### Detection Commands

```bash
# Find multer configuration
rg -n "multer\(|upload\.(single|array|fields)" --glob "*.{js,ts}"

# Find configurations missing fileFilter
rg -A10 "multer\(" --glob "*.{js,ts}" | grep -v "fileFilter"
```

---

## Reference Resources

- [OWASP NodeGoat](https://github.com/OWASP/NodeGoat)
- [Node.js Security Checklist](https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html)
- [npm Security Best Practices](https://docs.npmjs.com/packages-and-references/securing-your-code)
- [Prototype Pollution Attack](https://portswigger.net/daily-swig/prototype-pollution)
