Skip to content
cccskills
FreePublished on GitHub

node-typescript-security-pitfalls

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 install

Files included (1)

  • SKILL.md6.3 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Node and TypeScript Security Pitfalls

Overview

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.

1. Runtime Types Are Not Declared Types

// ❌ ?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.

2. child_process (CWE-78, CWE-88)

// ❌ 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 …).

3. Raw Queries in Safe ORMs (CWE-89)

LibraryUnsafeSafe
Prisma$queryRawUnsafe, $executeRawUnsafe, Prisma.raw()$queryRaw tagged template, model methods
TypeORMquery("… " + x), .where(\id = ${id}`)`.where("id = :id", { id })
Sequelizesequelize.query(\… ${x}`), literal(x)`replacements / bind
Knexknex.raw(\… ${x}`)`knex.raw("… ?", [x])
Drizzlesql.raw(x)sql\… ${x}``

Mongo/Mongoose: operator injection from JSON bodies (section 1), $where.

4. Next.js Server Actions and Route Handlers

  • Every exported async function in a "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 } });
}
  • Authorization done only in 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.
  • Server components passing whole records to client components serialise every field into the page payload.
  • NEXT_PUBLIC_* variables are shipped to the browser.

5. Prototype Pollution (CWE-1321) — high confidence only

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

6. Templates and Rendering

  • EJS <%- 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.
  • User-controlled template source compiled with Handlebars.compile, pug.compile, ejs.render.

7. Sandboxes and Code Loading

  • 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.

8. HTTP Clients and Tokens

  • axios: an absolute URL passed where a path was expected overrides baseURL and sends the configured auth headers to that host (CVE-2025-27152 class) — validate that user-supplied paths are relative.
  • Redirect following by default in axios/got/node-fetch on user URLs (ssrf-and-url-allowlists).
  • 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.

9. Express and Fastify Specifics

  • 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 }).
  • Multer file.originalname used as the stored path.
  • A route registered before app.use(authMiddleware) runs without it.

Common Mistakes

  • Reporting $queryRaw tagged templates, TypeORM parameters or execFile arrays as injection.
  • Reporting prototype pollution with no gadget.
  • Reporting JSON.parse as unsafe deserialization.
  • Missing that a server action is reachable without the page that renders it.

Red Flags

  • Template literals inside 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.

References (names and links only)

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

Reviews

No reviews yet. Tell others what you thought.

Comments

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.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

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.

makifbaysal/tasktrooper117Updated Oct 18, 2026

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.

makifbaysal/tasktrooper117Updated Oct 18, 2026

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.

makifbaysal/tasktrooper117Updated Oct 18, 2026

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.

makifbaysal/tasktrooper117Updated Oct 18, 2026

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.

makifbaysal/tasktrooper117Updated Oct 18, 2026

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.

makifbaysal/tasktrooper117Updated Oct 18, 2026

See all skills by makifbaysal

Report a problem with this skill