{"record":{"id":"a53ebac04201d4bf","repo":"paperclipai/paperclip","slug":"import-modulepath-escapes-plugin-root-and-is","errorCode":null,"errorMessage":"Import '${modulePath}' escapes plugin root and is not allowed","messagePattern":"Import '(.+?)' escapes plugin root and is not allowed","errorType":"exception","errorClass":"PluginSandboxError","httpStatus":null,"severity":"error","filePath":"server/src/services/plugin-runtime-sandbox.ts","lineNumber":99,"sourceCode":"  const entrypointPath = path.resolve(options.entrypointPath);\n  const pluginRoot = path.dirname(entrypointPath);\n\n  const context = vm.createContext({\n    ...DEFAULT_GLOBALS,\n    ...options.allowedGlobals,\n  });\n\n  const moduleCache = new Map<string, Record<string, unknown>>();\n  const allowedModules = options.allowedModules ?? {};\n\n  const realPluginRoot = realpathSync(pluginRoot);\n\n  const loadModuleSync = (modulePath: string): Record<string, unknown> => {\n    const resolvedPath = resolveModulePathSync(path.resolve(modulePath));\n    const realPath = realpathSync(resolvedPath);\n\n    if (!isWithinRoot(realPath, realPluginRoot)) {\n      throw new PluginSandboxError(\n        `Import '${modulePath}' escapes plugin root and is not allowed`,\n      );\n    }\n\n    const cached = moduleCache.get(realPath);\n    if (cached) return cached;\n\n    const code = readModuleSourceSync(realPath);\n\n    if (looksLikeEsm(code)) {\n      throw new PluginSandboxError(\n        \"Sandbox loader only supports CommonJS modules. Build plugin worker entrypoints as CJS for sandboxed loading.\",\n      );\n    }\n\n    const module = { exports: {} as Record<string, unknown> };\n    // Cache the module before execution to preserve CommonJS cycle semantics.\n    moduleCache.set(realPath, module.exports);","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/server/src/services/plugin-runtime-sandbox.ts#L81-L117","documentation":"Sandbox escape guard in loadModuleSync: realpath-resolved module path is not within the plugin's real root, so the import would read code outside the plugin. Blocks symlink/path traversal out of the sandbox; the escaping import specifier is at fault.","triggerScenarios":"Thrown at server/src/services/plugin-runtime-sandbox.ts:99 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Keep imports inside the plugin root; replace relative paths that traverse above the plugin directory ('../..') with allowed module specifiers."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"120ae5428fa29bee300bcf806491cd4d965fbb7c","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}