IntentiAI

Untrusted input reaching SQL, HTML, a shell or eval

Untrusted data reaching SQL, HTML, a shell, eval or an outbound URL.

Check injection-sinkShip CheckJavaScript, TypeScript, Python, PHP, Ruby

Why it matters

Models know the dangerous APIs well; they are the shortest way to write the feature. A template literal inside db.query, an innerHTML assignment, exec with an interpolated command, or pickle.loads on a request body all work on the first try with friendly input, so the agent moves on.

With hostile input they become the attacker's code. A quote character ends your SQL statement and starts theirs, a script tag runs in another user's session, a semicolon in a shell string starts a second command, and a URL taken from the request points your server at internal services or the cloud metadata endpoint.

Example

 router.get("/orders", async (req, res) => {
   const { status, sort } = req.query;
-  const rows = await db.query(
-    "SELECT * FROM orders WHERE status = $1 ORDER BY created_at",
-    [status],
-  );
+  const rows = await db.query(`SELECT * FROM orders WHERE status = '${status}' ORDER BY ${sort}`);
   res.json(rows);
 });

What it detects

  • SQL: a query, execute or raw call whose first argument contains a SQL keyword and is assembled at runtime (template interpolation, f-string, .format, % or +). Tagged sql templates and placeholder builders are left alone.
  • HTML: innerHTML, outerHTML, insertAdjacentHTML, document.write, dangerouslySetInnerHTML, v-html, mark_safe, Markup and |safe given a non-constant value, unless a sanitizer such as DOMPurify or escape appears on the line.
  • Shell and code execution: exec and execSync, os.system, subprocess or spawn with shell enabled and an assembled command; pickle, PyYAML yaml.load without a safe loader, eval, new Function, vm.run*, PHP unserialize and Ruby Marshal.load on a non-literal value.
  • SSRF: fetch, axios, requests, httpx or urlopen called with a variable the same hunk shows coming from the request, unless it looks like configuration.
  • Severity rises when the value visibly comes from the request (req.query, request.args, searchParams, handler parameters). Findings in test files are rated low, and sink names inside strings, comments and rule tables are ignored.

What to do when it fires

Keep data and code separate at the sink. Pass SQL values as bound parameters or through a tagged sql template. Set text with textContent or normal JSX rather than raw HTML, or sanitize with DOMPurify. Call processes with an argument array and no shell.

Replace eval and unsafe deserialization with JSON parsing or a lookup table. For outbound requests, check the URL against an allow-list of hostnames and reject private, loopback and link-local addresses before fetching.

Untrusted input reaching SQL, HTML, a shell or eval: AI code review check | IntentiAI