SkillTotal

Is Next.js safe?

No malicious indicators - review capabilities before installing
Notable — review in context (capabilities are not malware):
  • 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

npm_package · npm:next
LOW
0
/ 100 risk score
Snapshot · scanned Aug 18, 2026 · next@16.3.1 · engine 0.39.1 / ruleset 43

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.

Capabilities — what this component can do (not a risk score):
dynamic code executionfilesystem readfilesystem writemcp tools detectednetwork egressshell execution

Behavioral traits

How this component maps to the CSA agentic threat model. Descriptive — it never affects the risk score.

Tool surface
Tool Usage
Execution authority
Tool Access Control / Direct Tool Access
Filesystem reach
Tool Execution Context
Network egress
Interaction & Communication / Direct Communication

Findings (6)

HIGHNode.js dynamic code executionST-DYN-NODE

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)});`));
(()=>{"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.

HIGHNode.js shell/command executionST-SHELL-NODE

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 _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
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];

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.

MEDIUMNode.js filesystem readST-FS-NODE-READ

The component reads files from disk.

(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'));
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.

MEDIUMNode.js filesystem write/deleteST-FS-NODE-WRITE

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

MEDIUMNode.js network egressST-NET-NODE

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
* out-of-band client-side fetches (e.g. `fetch('/api/data')` inside a
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, {
const res = await import_undici.default.fetch(resource, addDuplexToInit(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.

LOWMCP tool surface detectedST-MCP-DETECTED

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 component

How we determine this: deterministic static analysis (regex + AST), evidence-anchored, no code execution. Methodology →