Is Next.js safe?
- Node.js shell/command execution
- Node.js dynamic code execution
- Node.js filesystem read
next is an AI npm_package analyzed by SkillTotal's deterministic static scanner. The scan found no malicious indicators, though 6 risky constructs are reported for review. It can: dynamic code execution, filesystem read, filesystem write, mcp tools detected, network egress and shell execution — capabilities are what the code can do, not a verdict on intent. Risk score 0/100 (low).
next 16.3.1
Automated static-analysis result. It can contain false positives and false negatives, and is not a claim about the intent of Next.js's authors. Report a false positive.
Behavioral traits
How this component maps to the CSA agentic threat model. Descriptive — it never affects the risk score.
Findings (6)
The code turns strings into live code at runtime (eval / new Function / exec).
* It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
return result(new RawSource(`eval(${compilation.outputOptions.trustedTypes ? `${_webpack.RuntimeGlobals.createScript}(${JSON.stringify(content + footer)})` : JSON.stringify(content + footer)});`));eval(getModuleCode)(
(()=>{"use strict";var __webpack_modules__={994:(e,r)=>{Object.defineProperty(r,"__esModule",{value:true});r.PARENT_MESSAGE_SETUP_ERROR=r.PARENT_MESSAGE_OK=r.PARENT_MESSAGE_CUSTOM=r.PARENT_MESSAGE_CLIENT_ERROR=r.CHILD_MESSAGE_INITIALIZE=r.C …(()=>{"use strict";var __webpack_modules__={994:(e,r)=>{Object.defineProperty(r,"__esModule",{value:true});r.PARENT_MESSAGE_SETUP_ERROR=r.PARENT_MESSAGE_OK=r.PARENT_MESSAGE_CUSTOM=r.PARENT_MESSAGE_CLIENT_ERROR=r.CHILD_MESSAGE_INITIALIZE=r.C …(()=>{var __webpack_modules__={803:e=>{"use strict";class LoadingLoaderError extends Error{constructor(e){super(e);this.name="LoaderRunnerError";Error.captureStackTrace(this,this.constructor)}}e.exports=LoadingLoaderError},349:(module,__unu …"eval() is not supported in this environment. If this page was served with a `Content-Security-Policy` header, make sure that `unsafe-eval` is included. React requires eval() in development mode for various debugging features like reconstru …
"eval() is not supported in this environment. React requires eval() in development mode for various debugging features like reconstructing callstacks from a different environment.\nReact will never use eval() in production mode"
"eval() is not supported in this environment. This can happen if you started the Node.js process with --disallow-code-generation-from-strings, or if `eval` was patched by other means. React requires eval() in development mode for various de …
"eval() is not supported in this environment. If this page was served with a `Content-Security-Policy` header, make sure that `unsafe-eval` is included. React requires eval() in development mode for various debugging features like reconstru …
"eval() is not supported in this environment. React requires eval() in development mode for various debugging features like reconstructing callstacks from a different environment.\nReact will never use eval() in production mode"
"eval() is not supported in this environment. This can happen if you started the Node.js process with --disallow-code-generation-from-strings, or if `eval` was patched by other means. React requires eval() in development mode for various de …
"eval() is not supported in this environment. If this page was served with a `Content-Security-Policy` header, make sure that `unsafe-eval` is included. React requires eval() in development mode for various debugging features like reconstru …
"eval() is not supported in this environment. React requires eval() in development mode for various debugging features like reconstructing callstacks from a different environment.\nReact will never use eval() in production mode"
"eval() is not supported in this environment. This can happen if you started the Node.js process with --disallow-code-generation-from-strings, or if `eval` was patched by other means. React requires eval() in development mode for various de …
"eval() is not supported in this environment. If this page was served with a `Content-Security-Policy` header, make sure that `unsafe-eval` is included. React requires eval() in development mode for various debugging features like reconstru …
"eval() is not supported in this environment. React requires eval() in development mode for various debugging features like reconstructing callstacks from a different environment.\nReact will never use eval() in production mode"
"eval() is not supported in this environment. This can happen if you started the Node.js process with --disallow-code-generation-from-strings, or if `eval` was patched by other means. React requires eval() in development mode for various de …
(function(){"use strict";var __webpack_modules__={600:function(e,t,s){const n=s(742);e.exports=n.default},742:function(e,t,s){Object.defineProperty(t,"__esModule",{value:true});t["default"]=void 0;var n=_interopRequireDefault(s(16));var o=_ …(function(){var e={166:function(){(function(e,t){"use strict";if(e.setImmediate){return}var n=1;var a={};var s=false;var i=e.document;var r;function setImmediate(e){if(typeof e!=="function"){e=new Function(""+e)}var t=new Array(arguments.le …(function(){var __webpack_modules__={285:function(__unused_webpack_module,exports){var indexOf=function(e,t){if(e.indexOf)return e.indexOf(t);else for(var r=0;r<e.length;r++){if(e[r]===t)return r}return-1};var Object_keys=function(e){if(Obj …* It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
return result(new RawSource(`eval(${compilation.outputOptions.trustedTypes ? `${RuntimeGlobals.createScript}(${JSON.stringify(content + footer)})` : JSON.stringify(content + footer)});`));Why it matters: If those strings aren't fixed and trusted, they become a way to run arbitrary code.
Fix: Avoid evaluating dynamically constructed code; if unavoidable, ensure the input is a trusted constant and never derived from external data.
The component can run operating-system commands or spawn processes.
const fileExt = ((_fileExtensionRegex_exec = fileExtensionRegex.exec(filename)) == null ? void 0 : _fileExtensionRegex_exec[1]) || 'unknown';
if (isJsonFile.exec(configFilePath)) {} else if (isJsFile.exec(configFilePath)) {"trimStart"in String.prototype||(String.prototype.trimStart=String.prototype.trimLeft),"trimEnd"in String.prototype||(String.prototype.trimEnd=String.prototype.trimRight),"description"in Symbol.prototype||Object.defineProperty(Symbol.protot …
const parsed = page_name_regex.exec(error);
const match = ignoredRegex.exec(pluginPath);
const match = /^[^?]+\.([^?]+)$/.exec(resource);
const res = regexCssError.exec(err.message);
const res = regexScssError.exec(err.message);
const _child_process = require("child_process");const _child_process = /*#__PURE__*/ _interop_require_default(require("child_process"));return _child_process.default.execSync(`${binaryName} --version`).toString().trim();const proc = spawn(tool.bin, [
const _child_process = require("child_process");// In this function we spawn (but do not await) all the network requests that
const res = /(.*)\s+[([].*/.exec(name);
for(let match; match = viewportWidthRe.exec(sizes); match){const parsedToken = parseHashWithOptions.exec(token);
const parsedToken = parseHashWithOptions.exec(token);
exec(input?: URLPatternInput, baseURL?: string): URLPatternResult | null;
const newSubset = (_a = /\/\* (.+?) \*\//.exec(line)) === null || _a === void 0 ? void 0 : _a[1];
const googleFontFileUrl = (_b = /src: url\((.+?)\)/.exec(line)) === null || _b === void 0 ? void 0 : _b[1];
const ext = /\.(woff|woff2|eot|ttf|otf)$/.exec(googleFontFileUrl)[1];
const ext = (_a = /\.(woff|woff2|eot|ttf|otf)$/.exec(fontFile.path)) === null || _a === void 0 ? void 0 : _a[1];
var match = tokens.exec(cssText);
Why it matters: Powerful and often legitimate — confirm the commands aren't built from untrusted input.
Fix: Confirm the command and its arguments are fully controlled and not derived from untrusted input; prefer execFile with an argument array.
The component reads files from disk.
fs.readFile(file, (err, data)=>{fs.readFile(
(function(){"use strict";var __webpack_modules__={600:function(e,t,s){const n=s(742);e.exports=n.default},742:function(e,t,s){Object.defineProperty(t,"__esModule",{value:true});t["default"]=void 0;var n=_interopRequireDefault(s(16));var o=_ …fs.readFile(__nccwpck_require__.ab + "mappings.wasm", null, (error, data) => {const clientHashes = bundler === Bundler.Turbopack && config.supportsImmutableAssets ? JSON.parse(await fs.readFile(path.join(distDir, 'immutable-static-hashes.json'), 'utf8')) : undefined;
const meta = isAppPage ? JSON.parse(await fs.readFile(path.join(appDistDir, `${basename}.meta`), 'utf8').catch(()=>'{}')) : {};const { files, fileHashes, entryHash } = await JSON.parse(await fs.readFile(traceFilePath, 'utf8'));hash.update(await fs.readFile(filePath));
return await fs.readFile(p, 'utf8');
const existingTrace = JSON.parse(await fs.readFile(traceOutputPath, 'utf8'));
const traceContent = JSON.parse(await fs.readFile(traceFile, 'utf8'));
return fs.readFile(filePath, 'utf8');
return await fs.readFile(path.join(distDir, BUILD_ID_FILE), 'utf8');
const middlewareNft = JSON.parse(await fs.readFile(path.join(distDir, SERVER_DIRECTORY, 'middleware.js.nft.json'), 'utf8'));
let content = await fs.readFile(templatePath);
return fs.readFileSync(lockfilePath, 'utf-8');
appPathsManifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
const packageJsonContent = await fs.readFile(/* turbopackIgnore: true */ packageJsonPath, 'utf8');
const traceData = JSON.parse(await fs.readFile(/* turbopackIgnore: true */ traceFilePath, 'utf8'));
const EXTERNAL_PACKAGES = JSON5.parse(fs.readFileSync(path.join(__dirname, '../lib/server-external-packages.jsonc'), 'utf8'));
fs.readFile(file, (err, data)=>{imageData.alt = await fs.readFile(altPath, 'utf8');
const content = await fs.readFile(this.filePath, 'utf8');
...await fs.readFile(manifestPath, 'utf8').then((res)=>JSON.parse(res)).catch(()=>({})),Why it matters: Usually legitimate, but worth confirming it can't be steered into reading sensitive files.
Fix: Confirm which files are read and that paths cannot be influenced by untrusted input to reach sensitive locations.
The component writes or deletes files on disk.
await fs.writeFile(rscFallbackPath, '{}');await fs.writeFile(traceOutputPath, JSON.stringify({fs.writeFile(nextServerTraceOutput, JSON.stringify({fs.writeFile(nextMinimalTraceOutput, JSON.stringify({await fs.writeFile(traceFile, JSON.stringify({await fs.writeFile(filePath, content, 'utf-8');
await fs.unlink(serverBundle);
fs.rm(path.join(distDir, SERVER_DIRECTORY, 'pages', `${normalizedPath}.html`), {fs.rm(path.join(distDir, SERVER_DIRECTORY, 'pages', `${normalizedPath}.json`), {await fs.unlink(path.join(distDir, EXPORT_DETAIL)).catch((err)=>{await fs.writeFile(path.join(distDir, SERVER_DIRECTORY, 'middleware.js.nft.json'), JSON.stringify(middlewareNft));
await fs.writeFile(path.join(diagnosticsDir, ROUTE_BUNDLE_STATS_FILE), JSON.stringify(rows, null, 2));
await fs.writeFile(path.join(distDir, 'turbopack'), '');
await fs.writeFile(path.join(distDir, 'package.json'), '{"type": "commonjs"}');await fs.writeFile(configTraceFile, JSON.stringify({await fs.rm(outputPath, {await fs.writeFile(packageJsonOutputPath, packageJsonContent);
await fs.writeFile(serverOutputPath, `${moduleType ? `performance.mark('next-start');await Promise.all(files.map((name)=>name !== INVALIDATION_MARKER ? fs.rm(path.join(cacheDirectory, name), {await fs.rm(path.join(cacheDirectory, INVALIDATION_MARKER), {await fs.writeFile(manifestPath, JSON.stringify({await fs.rm(outDir, {await fs.writeFile(join(distDir, EXPORT_DETAIL), formatManifest({await fs.writeFile(join(distDir, EXPORT_DETAIL), formatManifest({writeFile: (filePath, data)=>fs.writeFile(filePath, data),
Why it matters: Usually legitimate, but worth confirming the paths can't be controlled by untrusted input.
Fix: Confirm which files are written/deleted and that paths cannot be influenced by untrusted input.
The component makes outbound network requests.
const _nodehttp = /*#__PURE__*/ _interop_require_default(require("node:http"));import type { IncomingMessage, ServerResponse } from 'node:http';import type { IncomingMessage, ServerResponse } from 'node:http';import type { IncomingMessage, ServerResponse } from 'node:http';(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,{otherChunks:["static/chunks/0.8z-24o~zj6q.js","static/chunks/0qgq.-.c2spwh.js","static/chunks/0u_y6vsc_oa5w.js"],runtimeModuleI …res = await fetch(`http://127.0.0.1:${port}/mcp`, {const _nodehttp = /*#__PURE__*/ _interop_require_default(require("node:http"));const tokenRes = await fetch(uploadUrl, {const res = await fetch(`${registry}-/package/next/dist-tags`);const response = await fetch(endpoint).catch((error)=>{* Returns true if the error from a fetch() rejection indicates a network
* Shared by the initial fetch (`fetchSegmentsOnCacheMiss`) and the localized
return fetch(input, init);
* out-of-band client-side fetches (e.g. `fetch('/api/data')` inside areturn fetch(input, init);
fetch(`${assetPrefix}/_next/static/development/_devPagesManifest.json`).then((res)=>res.json()).then((manifest)=>{this.promisedDevPagesManifest ||= fetch(`${this.assetPrefix}/_next/static/development/${_constants.DEV_CLIENT_PAGES_MANIFEST}`, {this.promisedMiddlewareMatchers = fetch(`${this.assetPrefix}/_next/static/${this.buildId}/${_constants.DEV_CLIENT_MIDDLEWARE_MANIFEST}`, {styleSheets.set(href, prom = fetch(href, {async function fetch(resource, options) {const res = await import_undici.default.fetch(resource, addDuplexToInit(options));
async function fetch(resource, options) {const res = await import_undici.default.fetch(resource, addDuplexToInit(options));
const node_http_1 = __importDefault(require("node:http"));const node_https_1 = __importDefault(require("node:https"));Why it matters: Usually legitimate, but confirm the destinations are expected and no sensitive data leaves.
Fix: Confirm the destination hosts are expected and that no sensitive data is sent off-host.
An MCP tool surface (manifest or tool definitions) was found.
mcpServer.registerTool('query_spans', {{"version":3,"sources":["../../../src/cli/internal/turbo-trace-server.ts"],"sourcesContent":["import http from 'node:http'\nimport z from 'next/dist/compiled/zod'\nimport { loadBindings } from '../../build/swc'\nimport type { TraceSpanInfo …server.registerTool('compile_route', {{"version":3,"sources":["../../../../../src/server/mcp/tools/compile-route.ts"],"sourcesContent":["/**\n * MCP tool for compiling a specific route via the on-demand entry handler.\n *\n * Triggers on-demand compilation so the route's assets …server.registerTool('get_compilation_issues', {{"version":3,"sources":["../../../../../src/server/mcp/tools/get-compilation-issues.ts"],"sourcesContent":["/**\n * MCP tool for getting compilation issues from all routes via Turbopack.\n *\n * Unlike get_errors (which requires a browser s …server.registerTool('get_errors', {{"version":3,"sources":["../../../../../src/server/mcp/tools/get-errors.ts"],"sourcesContent":["/**\n * MCP tool for retrieving error state from Next.js dev server.\n *\n * This tool provides comprehensive error reporting including:\n * - N …server.registerTool('get_logs', {{"version":3,"sources":["../../../../../src/server/mcp/tools/get-logs.ts"],"sourcesContent":["/**\n * MCP tool for getting the path to the Next.js development log file.\n *\n * This tool returns the path to the {nextConfig.distDir}/logs/nex …server.registerTool('get_page_metadata', {{"version":3,"sources":["../../../../../src/server/mcp/tools/get-page-metadata.ts"],"sourcesContent":["import type { McpServer } from 'next/dist/compiled/@modelcontextprotocol/sdk/server/mcp'\nimport {\n HMR_MESSAGE_SENT_TO_BROWSER,\n typ …server.registerTool('get_project_metadata', {{"version":3,"sources":["../../../../../src/server/mcp/tools/get-project-metadata.ts"],"sourcesContent":["import type { McpServer } from 'next/dist/compiled/@modelcontextprotocol/sdk/server/mcp'\nimport { mcpTelemetryTracker } from '../mcp- …server.registerTool('get_request_insights', {{"version":3,"sources":["../../../../../src/server/mcp/tools/get-request-insights.ts"],"sourcesContent":["import type { McpServer } from 'next/dist/compiled/@modelcontextprotocol/sdk/server/mcp'\nimport z from 'next/dist/compiled/zod'\nimpo …server.registerTool('get_routes', {{"version":3,"sources":["../../../../../src/server/mcp/tools/get-routes.ts"],"sourcesContent":["/**\n * MCP tool for getting all routes that become entry points in a Next.js application.\n *\n * This tool discovers routes by scanning the fi …server.registerTool('get_server_action_by_id', {{"version":3,"sources":["../../../../../src/server/mcp/tools/get-server-action-by-id.ts"],"sourcesContent":["import type { McpServer } from 'next/dist/compiled/@modelcontextprotocol/sdk/server/mcp'\nimport { z } from 'next/dist/compiled/zod …server.registerTool('compile_route', {{"version":3,"sources":["../../../../src/server/mcp/tools/compile-route.ts"],"sourcesContent":["/**\n * MCP tool for compiling a specific route via the on-demand entry handler.\n *\n * Triggers on-demand compilation so the route's assets ar …server.registerTool('get_compilation_issues', {{"version":3,"sources":["../../../../src/server/mcp/tools/get-compilation-issues.ts"],"sourcesContent":["/**\n * MCP tool for getting compilation issues from all routes via Turbopack.\n *\n * Unlike get_errors (which requires a browser sess …server.registerTool('get_errors', {Why it matters: Just context — review which tools it offers and their permissions.
Fix: Review the declared MCP tools and their permissions.
Check your own component
Run the same evidence-backed scan on any MCP server, agent skill, or package.
Scan your own componentHow we determine this: deterministic static analysis (regex + AST), evidence-anchored, no code execution. Methodology →