ansible-automation-eng…
Ansible automation: playbooks, roles, collections, Molecule testing, Vault security.
Secure-by-default patterns for Node.js backend applications. Each section shows what correct code looks like and why it matters. Load this reference when the task involves security, auth, injection, XSS, CSRF, SSRF, prototype pollution, or any vulnerability-related code.
$ npx -y skills add notque/vexjoy-agent --agent claude-codeHow it fires
How this agent gets triggered: by you, by Claude, or both.
Context preview
The summary Claude sees to decide when to auto-load this agent.
Secure-by-default patterns for Node.js backend applications. Each section shows what correct code looks like and why it matters. Load this reference when the task involves security, auth, injection, XSS, CSRF, SSRF, prototype pollution, or any vulnerability-related code.
Secure-by-default patterns for Node.js backend applications. Each section shows what correct code looks like and why it matters. Load this reference when the task involves security, auth, injection, XSS, CSRF, SSRF, prototype pollution, or any vulnerability-related code.
---
Use `execFile` or `spawn` (with `shell: false`, the default) for subprocess calls. These pass arguments as separate argv entries without invoking a shell.
import { execFile, execFileSync, spawn } from 'child_process';
// Correct: execFile passes args directly to the binary
execFile('git', ['clone', '--', userUrl], (err, stdout) => {
if (err) console.error('clone failed:', err.message);
});
// Correct: spawn with default shell: false
const child = spawn('convert', [userInput, 'output.png']);
// Correct: execFileSync for synchronous operations
const output = execFileSync('git', ['log', '--oneline', '-5']);**Why this matters**: `exec` and `execSync` always invoke a shell, where metacharacters (`;`, `|`, `&`, `$()`) are interpreted. On Windows, `spawn`/`execFile` targeting `.bat`/`.cmd` files implicitly route through `cmd.exe` regardless of the `shell` option (CVE-2024-27980, fixed in Node 18.20.0 / 20.12.0 / 21.7.0).
**Detection**:
rg -n '\bexec\(|\bexecSync\(' . --type ts --type js
rg -n 'shell:\s*true' . --type ts --type js---
Use Zod or similar schema validation before merging user input into objects. For key-value stores with user-controlled keys, use `Map` or `Object.create(null)`.
import { z } from 'zod';
// Correct: validate shape with Zod before any merge
const ConfigSchema = z.object({
theme: z.enum(['light', 'dark']).optional(),
language: z.string().max(5).optional(),
});
const validated = ConfigSchema.parse(req.body);
const merged = { ...defaultConfig, ...validated };
// Correct: use Map for user-controlled keys
const userSettings = new Map<string, unknown>();
for (const [key, value] of Object.entries(validatedInput)) {
userSettings.set(key, value);
}
// Correct: prototype-free object for lookups
const lookup = Object.create(null) as Record<string, string>;**Why this matters**: Deep-merging `req.body` into objects without filtering `__proto__`, `constructor`, or `prototype` keys pollutes `Object.prototype`. Downstream code that reads properties from shared objects (template engines, HTTP clients, auth checks) picks up attacker-injected values. CVE-2019-10744 (lodash `defaultsDeep`), CVE-2019-19919 (Handlebars compile-time RCE), and CVE-2026-40175 (axios header injection bypassing IMDSv2) demonstrate the full attack chain.
**Detection**:
rg -n '_\.(merge|defaultsDeep|set|setWith)\(.*req\.' . --type ts --type js rg -n 'Object\.assign\(.*req\.' . --type ts --type js rg -n 'for\s*\(.*Object\.keys\(.*req\.' . --type ts --type js
---
Mount authentication middleware before route handlers. Middleware executes in registration order; auth mounted after a route leaves that route unprotected.
import express from 'express';
import helmet from 'helmet';
import rateLimit from 'express-rate-limit';
const app = express();
// 1. Security headers first
app.use(helmet());
// 2. Body parsing
app.use(express.json({ strict: true }));
// 3. Rate limiting
app.use('/api/', rateLimit({
windowMs: 60_000,
max: 100,
standardHeaders: true,
}));
// 4. Auth middleware BEFORE routes
app.use('/api/', authMiddleware);
// 5. Routes come last
app.use('/api/users', userRouter);
app.use('/api/invoices', invoiceRouter);
// 6. Error handler at the end
app.use(errorHandler);**Why this matters**: Express processes middleware in the order registered. If a route is mounted before auth middleware, requests to that route bypass authentication entirely. This is the Express-equivalent of "forced browsing."
**Detection**:
rg -n 'app\.use\(' . --type ts --type js | head -30---
Always pass an explicit `algorithms` allowlist when verifying JWTs. Verify `exp`, `aud`, and `iss` claims. Use short-lived access tokens with refresh tokens for revocability.
import jwt from 'jsonwebtoken';
// Correct: pin algorithm, verify standard claims
const payload = jwt.verify(token, publicKey, {
algorithms: ['RS256'], // Pin to a single algorithm family
audience: 'api.example.com', // Verify audience
issuer: 'auth.example.com', // Verify issuer
});
// Correct: sign with explicit algorithm and short expiry
const token = jwt.sign(
{ sub: user.id, role: user.role },
privateKey,
{
algorithm: 'RS256',
expiresIn: '15m', // Short-lived access token
audience: 'api.example.com',
issuer: 'auth.example.com',
},
);**Why this matters**: `jwt.verify(token, key)` without `algorithms` allows the attacker to choose the algorithm. CVE-2022-23540 and CVE-2022-23541 (jsonwebtoken < 9.0.0) allowed `alg: none` verification and RS-to-HS key confusion. CVE-2022-29217 (PyJWT) had the same class of bug. Never include `"none"` in the algorithms list. Never mix HS and RS algorithms with a single key.
**Detection**:
rg -n 'jwt\.verify\(' . --type ts --type js | rg -v 'algorithms'
rg -n 'jwt\.decode\(' . --type ts --type js
rg -n "algorithms.*none" . --type ts --type js---
Resolve hostnames to IPs and validate against private/internal ranges before making outbound requests. Disable redirect following or re-validate on each hop.
import { lookup } from 'dns/promises';
import ipaddr from 'ipaddr.js';
const DISALLOWED_RANGES = ['private', 'linkLocal', 'loopback', 'uniqueLocal', 'unspecified'];
async function safeFetch(userUrl: string): Promise<Response> {
const url = new URL(userUrl)Essays and writing behind this toolkit live at vexjoy.com. VexJoy Agent connects plain-English requests to specialist agents, skills, and workflows. /do selects the knowledge and tools needed for your task.
Repo: notque/vexjoy-agent
Ansible automation: playbooks, roles, collections, Molecule testing, Vault security.
**Scope**: Module selection patterns, builtin vs command/shell decisions, collection modules, and version-specific module changes **Version range**:…
**Scope**: Molecule test scenarios, ansible-lint rules, idempotency validation, and check-mode patterns **Version range**: Molecule 6.0+ / ansible-lint 6.0+ /…
Universal rules injected by /do at dispatch. Each agent's .md file supplies domain rules.
**Scope**: Failure modes in agent output style — over-reporting, self-congratulation, verbose narration, and hedging. Covers what to detect and how to fix…
Zero-dependency combat visual upgrades: CSS particle replacement, Framer Motion combat juice, CSS 3D card transforms.