-
Notifications
You must be signed in to change notification settings - Fork 2k
JS: Add support for @vercel/node serverless functions #21697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,4 @@ | ||||||
| --- | ||||||
| category: newFeature | ||||||
| --- | ||||||
| * Added support for [`@vercel/node`](https://www.npmjs.com/package/@vercel/node) Vercel serverless functions. Handlers are recognised via the `VercelRequest`/`VercelResponse` TypeScript parameter types, and standard security queries (`js/reflected-xss`, `js/request-forgery`, `js/sql-injection`, `js/command-line-injection`, etc.) now detect vulnerabilities in Vercel API route files. | ||||||
|
||||||
| * Added support for [`@vercel/node`](https://www.npmjs.com/package/@vercel/node) Vercel serverless functions. Handlers are recognised via the `VercelRequest`/`VercelResponse` TypeScript parameter types, and standard security queries (`js/reflected-xss`, `js/request-forgery`, `js/sql-injection`, `js/command-line-injection`, etc.) now detect vulnerabilities in Vercel API route files. | |
| * Added support for [`@vercel/node`](https://www.npmjs.com/package/@vercel/node) Vercel serverless functions. Handlers are recognized via the `VercelRequest`/`VercelResponse` TypeScript parameter types, and standard security queries (`js/reflected-xss`, `js/request-forgery`, `js/sql-injection`, `js/command-line-injection`, etc.) now detect vulnerabilities in Vercel API route files. |
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,200 @@ | ||||||||||||||||
| /** | ||||||||||||||||
| * Provides classes for working with [@vercel/node](https://www.npmjs.com/package/@vercel/node) Vercel serverless functions. | ||||||||||||||||
| */ | ||||||||||||||||
|
|
||||||||||||||||
| import javascript | ||||||||||||||||
| import semmle.javascript.frameworks.HTTP | ||||||||||||||||
|
|
||||||||||||||||
| /** | ||||||||||||||||
| * Provides classes for working with [@vercel/node](https://www.npmjs.com/package/@vercel/node) Vercel serverless functions. | ||||||||||||||||
| * | ||||||||||||||||
| * A Vercel serverless function is a module whose default export is a function | ||||||||||||||||
| * with signature `(req: VercelRequest, res: VercelResponse) => void`, where | ||||||||||||||||
| * the types are imported from the `@vercel/node` package. The Vercel runtime | ||||||||||||||||
| * invokes the default export for every incoming HTTP request. | ||||||||||||||||
|
||||||||||||||||
| * with signature `(req: VercelRequest, res: VercelResponse) => void`, where | |
| * the types are imported from the `@vercel/node` package. The Vercel runtime | |
| * invokes the default export for every incoming HTTP request. | |
| * taking parameters `(req: VercelRequest, res: VercelResponse)`, where the | |
| * types are imported from the `@vercel/node` package. The default export may | |
| * be synchronous or `async`, and the Vercel runtime invokes it for every | |
| * incoming HTTP request. |
Outdated
Copilot
AI
Apr 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spelling consistency: this file uses British spelling (“recognised”), but the surrounding JavaScript framework libraries consistently use US spelling (“recognized”). Please change to “recognized” here (and keep wording consistent across related docs/tests).
| * are recognised by their TypeScript parameter types. The default-export | |
| * are recognized by their TypeScript parameter types. The default-export |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| req.hasUnderlyingType("@vercel/node", "VercelRequest") and | |
| res.hasUnderlyingType("@vercel/node", "VercelResponse") | |
| req.hasUnderlyingType(["@vercel/node", "@now/node"], ["NowRequest", "VercelRequest"]) and | |
| res.hasUnderlyingType(["@vercel/node", "@now/node"], ["NowResponse", "VercelResponse"]) |
After testing this on some code in the wild, it seems there are some deprecated aliases for these types worth covering here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the fast review! your request is addressed here cff0734
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import javascript | ||
|
|
||
| query predicate test_HeaderDefinition( | ||
| Http::HeaderDefinition hd, string name, VercelNode::RouteHandler rh | ||
| ) { | ||
| hd.getRouteHandler() = rh and name = hd.getAHeaderName() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import javascript | ||
|
|
||
| query predicate test_RedirectInvocation( | ||
| Http::RedirectInvocation call, DataFlow::Node url, VercelNode::RouteHandler rh | ||
| ) { | ||
| call.getRouteHandler() = rh and url = call.getUrlArgument() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import javascript | ||
|
|
||
| query predicate test_RequestInputAccess( | ||
| Http::RequestInputAccess ria, string kind, VercelNode::RouteHandler rh | ||
| ) { | ||
| ria.getRouteHandler() = rh and kind = ria.getKind() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import javascript | ||
|
|
||
| query predicate test_RequestSource(Http::Servers::RequestSource src, VercelNode::RouteHandler rh) { | ||
| src.getRouteHandler() = rh | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import javascript | ||
|
|
||
| query predicate test_ResponseSendArgument( | ||
| Http::ResponseSendArgument arg, VercelNode::RouteHandler rh | ||
| ) { | ||
| arg.getRouteHandler() = rh | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import javascript | ||
|
|
||
| query predicate test_ResponseSource(Http::Servers::ResponseSource src, VercelNode::RouteHandler rh) { | ||
| src.getRouteHandler() = rh | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| import javascript | ||
|
|
||
| query predicate test_RouteHandler(VercelNode::RouteHandler rh) { any() } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,8 @@ | ||||||
| import type { VercelRequest, VercelResponse } from "@vercel/node"; | ||||||
|
|
||||||
| // A default-exported function that has VercelRequest/VercelResponse at | ||||||
| // positions 1 and 2, not 0 and 1. Vercel does not invoke it this way, | ||||||
| // so it must NOT be recognised as a route handler. | ||||||
|
||||||
| // so it must NOT be recognised as a route handler. | |
| // so it must NOT be recognized as a route handler. |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,27 @@ | ||||||
| import type { VercelRequest, VercelResponse } from "@vercel/node"; | ||||||
|
|
||||||
| // A private helper with the same signature. Must NOT be recognised as a | ||||||
|
||||||
| // A private helper with the same signature. Must NOT be recognised as a | |
| // A private helper with the same signature. Must NOT be recognized as a |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| test_RouteHandler | ||
| | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| test_RequestSource | ||
| | src/vercel.ts:9:33:9:35 | req | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| test_ResponseSource | ||
| | src/vercel.ts:9:53:9:55 | res | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| | src/vercel.ts:23:3:23:17 | res.status(200) | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| test_HeaderDefinition | ||
| | src/vercel.ts:19:3:19:44 | res.set ... /html") | content-type | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| test_RedirectInvocation | ||
| | src/vercel.ts:26:3:26:39 | res.red ... string) | src/vercel.ts:26:16:26:38 | req.que ... string | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| test_RequestInputAccess | ||
| | src/vercel.ts:11:13:11:21 | req.query | parameter | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| | src/vercel.ts:12:13:12:20 | req.body | body | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| | src/vercel.ts:13:13:13:23 | req.cookies | cookie | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| | src/vercel.ts:14:13:14:19 | req.url | url | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| | src/vercel.ts:15:16:15:31 | req.headers.host | header | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| | src/vercel.ts:16:15:16:33 | req.headers.referer | header | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| | src/vercel.ts:26:16:26:24 | req.query | parameter | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| test_ResponseSendArgument | ||
| | src/vercel.ts:22:12:22:12 | q | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | | ||
| | src/vercel.ts:23:24:23:24 | b | src/vercel.ts:9:16:27:1 | functio ... ing);\\n} | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import RouteHandler | ||
| import RequestSource | ||
| import ResponseSource | ||
| import RequestInputAccess | ||
| import HeaderDefinition | ||
| import ResponseSendArgument | ||
| import RedirectInvocation |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import type { VercelRequest, VercelResponse } from "@vercel/node"; | ||
| import { exec } from "child_process"; | ||
|
|
||
| export default function handler(req: VercelRequest, res: VercelResponse) { | ||
| const name = req.query.name as string; // $ Source | ||
| exec("echo " + name, (err, stdout) => { // $ Alert | ||
| res.send(stdout); | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This row says “vercel”, but the added modeling is specifically for
@vercel/nodeserverless functions. Consider renaming the entry to be more specific (for example, “Vercel (@vercel/node)” or similar) to avoid implying broader Vercel platform coverage.