Loading...
Loading...
Write secure-by-default Node.js and TypeScript applications following security best practices. Use when: (1) Writing new Node.js/TypeScript code, (2) Creating API endpoints or middleware, (3) Handling user input or form data, (4) Implementing authentication or authorization, (5) Working with secrets or environment variables, (6) Setting up project configurations (tsconfig, eslint), (7) User mentions security concerns, (8) Reviewing code for vulnerabilities, (9) Working with file paths or child processes, (10) Setting up HTTP headers or CORS.
npx skill4agent add joacod/skills secure-node-typescriptreferences/security-index.md| Tier | When to Apply | Key Focus Areas |
|---|---|---|
| Always | All Node.js/TS code | Strict TypeScript, input validation, no hardcoded secrets, safe error handling |
| API/HTTP | Web endpoints, middleware | Headers (helmet), rate limiting, CORS, body limits, Content-Type validation |
| Auth | Authentication features | Password hashing (argon2), JWT validation, secure cookies, RBAC |
| Data | External data processing | SQL injection, XSS sanitization, prototype pollution, schema validation |
| Runtime | Dynamic code, processes | No eval, safe child_process, path traversal prevention |
// tsconfig.json
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noUncheckedIndexedAccess": true
}
}// DO: Schema validation at entry points
import { z } from 'zod'
const UserSchema = z.object({
email: z.string().email(),
age: z.number().int().min(0).max(150),
})
// In route handler
const result = UserSchema.safeParse(req.body)
if (!result.success) {
return res.status(400).json({ error: 'Invalid input' })
}
const user = result.data // Type-safe validated data// DON'T: String concatenation (SQL injection)
const query = `SELECT * FROM users WHERE id = ${userId}`
// DO: Parameterized queries
const result = await db.query('SELECT * FROM users WHERE id = $1', [userId])import argon2 from 'argon2'
// Hash password
const hash = await argon2.hash(password, { type: argon2.argon2id })
// Verify password
const valid = await argon2.verify(hash, password)import helmet from 'helmet'
import express from 'express'
const app = express()
app.use(helmet()) // Sets HSTS, CSP, X-Frame-Options, etc.
app.disable('x-powered-by')// DO: Enforce strict body limits
app.use(express.json({ limit: '1kb' })) // Adjust based on expected payload
// DON'T: Unlimited body parsing (DoS risk)
app.use(express.json())import path from 'node:path'
// DO: Resolve and validate paths
const ALLOWED_DIR = '/app/uploads'
const safePath = path.resolve(ALLOWED_DIR, userInput)
if (!safePath.startsWith(ALLOWED_DIR)) {
throw new Error('Path traversal attempt blocked')
}// DO: Generic error response to clients
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
console.error(err) // Log full error internally
res.status(500).json({ error: 'Internal server error' }) // Generic to client
})
// DON'T: Expose error details
res.status(500).json({ error: err.message, stack: err.stack })// DO: Load secrets from environment
import 'dotenv/config'
const dbPassword = process.env.DB_PASSWORD
if (!dbPassword) throw new Error('DB_PASSWORD required')
// DON'T: Hardcoded secrets
const dbPassword = 'secret123' // Never do this// DO: Explicit Node.js built-in imports (prevents typosquatting)
import { createServer } from 'node:http'
import { readFile } from 'node:fs/promises'
import path from 'node:path'
// DON'T: Implicit imports
import { createServer } from 'http' // Could resolve to malicious package| Task | Load Reference |
|---|---|
| Project setup, tsconfig, type safety | |
| Form validation, user input, API params | |
| Login, sessions, JWT, passwords, RBAC | |
| Headers, CORS, rate limiting, CSP | |
| eval, child_process, prototype pollution | |
| File uploads, path handling, regex | |
| npm audit, lockfiles, supply chain | |
| Error handling, logging, monitoring | |
| Linters, CI/CD, threat modeling | |
| Full guideline lookup | |
tsconfig.jsonpython3 scripts/audit-tsconfig.py /path/to/projectstrict: truenoImplicitAnystrictNullChecksnoUncheckedIndexedAccessassets/tsconfig.secure.jsoneslint-security.config.jsreferences/security-index.mdreferences/typescript-safety.mdreferences/input-validation.mdreferences/authentication.mdreferences/http-security.mdreferences/runtime-safety.mdreferences/filesystem-paths.mdreferences/dependencies.mdreferences/error-logging.mdreferences/operational.md