Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
The English summary is being prepared. Showing the original description.
Use when reviewing Node.js or TypeScript server code - Express/Fastify/Nest handlers, Next.js server actions and route handlers, child_process, ORM raw queries, prototype pollution, template engines, JWT and outbound HTTP clients
The English summary is being prepared. Showing the original description.
See how to installReview the instructions the agent will receive before you install.
TypeScript types vanish at runtime: req.query.id: string can arrive as an array or an object. Most Node findings come from that gap, from exec with a template string, from raw-query escape hatches in otherwise safe ORMs, and — in Next.js — from forgetting that a server action is a public endpoint.
// ❌ ?id[$ne]=x or ?id[]=a&id[]=b gives an object or array, not a string
const doc = await Orders.findOne({ id: req.query.id as string, owner: user.id });
// ✅ validate at the boundary (zod/valibot/class-validator) and coerce
const { id } = z.object({ id: z.string().uuid() }).parse(req.query);
Length, includes and equality checks on an unvalidated query value can be bypassed the same way.
// ❌ shell
exec(`convert ${file} out.png`);
spawn("git", ["clone", url], { shell: true });
// ✅ no shell, end of options
execFile("git", ["clone", "--", url, dir]);
Also check the env option for request-controlled keys (NODE_OPTIONS=--require …).
| Library | Unsafe | Safe |
|---|---|---|
| Prisma | $queryRawUnsafe, $executeRawUnsafe, Prisma.raw() | $queryRaw tagged template, model methods |
| TypeORM | query("… " + x), .where(\id = ${id}`)` | .where("id = :id", { id }) |
| Sequelize | sequelize.query(\… ${x}`), literal(x)` | replacements / bind |
| Knex | knex.raw(\… ${x}`)` | knex.raw("… ?", [x]) |
| Drizzle | sql.raw(x) | sql\… ${x}`` |
Mongo/Mongoose: operator injection from JSON bodies (section 1), $where.
"use server" file is a callable POST endpoint, whether or not a page renders a form for it. Each must authenticate and authorize inside the action.// ❌ the page is admin-only, the action is not
"use server";
export async function deleteUser(id: string) { await db.user.delete({ where: { id } }); }
// ✅
export async function deleteUser(id: string) {
const session = await auth();
if (session?.user.role !== "admin") throw new Error("forbidden");
await db.user.delete({ where: { id } });
}
middleware.ts: middleware matchers miss paths, and Next.js < 15.2.3 / 14.2.25 / 13.5.9 / 12.3.5 let an x-middleware-subrequest header skip middleware entirely (CVE-2025-29927). Check in the handler or data layer too.NEXT_PUBLIC_* variables are shipped to the browser.Report only with a gadget: a recursive merge/set of user JSON (lodash.merge, _.set with user paths, hand-written deep merge) where __proto__ or constructor.prototype reaches a property later read for an auth decision, a child_process option (shell, env), or a template option.
// ❌ deepMerge(defaults, req.body) with {"__proto__": {"isAdmin": true}}
// ✅ validate the body against a schema first; build lookups with Object.create(null) or Map
<%- user %>, Handlebars {{{ user }}}, Pug != user → XSS.res.render(view, req.query) or { ...req.body } as locals: template options ride along (EJS outputFunctionName/escapeFunction, CVE-2022-29078 class) → RCE.Handlebars.compile, pug.compile, ejs.render.vm/vm.runInNewContext is not a security boundary; vm2 is discontinued after sandbox escapes. Running user code in either is CRITICAL when reachable.eval, new Function, require(userPath), dynamic import(userPath).js-yaml 3.x load() instantiates JavaScript types (!!js/function) — safeLoad or js-yaml 4's load.node-serialize unserialize on input.baseURL and sends the configured auth headers to that host (CVE-2025-27152 class) — validate that user-supplied paths are relative.jsonwebtoken: jwt.decode does not verify; jwt.verify without algorithms.crypto.timingSafeEqual for MACs (throws on length mismatch — compare lengths first); Math.random for tokens.app.set("trust proxy", true) trusts every hop's X-Forwarded-For.express.static(".") or express.static(__dirname) serves source and .env.res.sendFile(path.join(dir, name)) instead of res.sendFile(name, { root: dir }).file.originalname used as the stored path.app.use(authMiddleware) runs without it.$queryRaw tagged templates, TypeORM parameters or execFile arrays as injection.JSON.parse as unsafe deserialization.exec(, query(, raw(, $queryRawUnsafe(.shell: true."use server" files with exported mutations and no auth() call inside them.as string on req.query / req.params values used in a query.merge(, defaultsDeep(, set( fed with req.body.Node.js security best practices · Next.js data security · CVE-2025-29927, CVE-2025-27152, CVE-2022-29078 · CWE-78, 89, 1321 · OWASP Top 10:2025
No reviews yet. Tell others what you thought.
No login needed. Share how it worked for you, ask a question, or note where it did not run.
No comments yet. Be the first to write one.
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
The English summary is being prepared. Showing the original description.
Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping
The English summary is being prepared. Showing the original description.
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
The English summary is being prepared. Showing the original description.
Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task
The English summary is being prepared. Showing the original description.
How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.
The English summary is being prepared. Showing the original description.
Use when the repository keeps its alerting in code, or a person asks for alerts outside TaskTrooper - PrometheusRule YAML, a Cloud Monitoring alert policy in Terraform, a Datadog monitor, each routed to TaskTrooper's alert ingest URL so it opens an incident here
The English summary is being prepared. Showing the original description.