{"record":{"id":"7c1510133846a8c5","repo":"mastra-ai/mastra","slug":"plugin-entry-must-be-inside-the-plugin-directory","errorCode":null,"errorMessage":"Plugin entry must be inside the plugin directory","messagePattern":"Plugin entry must be inside the plugin directory","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/plugins/install.ts","lineNumber":156,"sourceCode":"      const detectedEntry = tryDetectEntry(pluginDir);\n      return detectedEntry ? [{ name: entry.name, path: pluginDir, entry: detectedEntry }] : [];\n    });\n}\n\nfunction tryDetectEntry(pluginDir: string): string | undefined {\n  try {\n    return detectEntry(pluginDir);\n  } catch {\n    return undefined;\n  }\n}\n\nexport function detectEntry(pluginDir: string, explicitEntry?: string): string {\n  const root = path.resolve(pluginDir);\n  if (explicitEntry) {\n    const entryPath = path.resolve(pluginDir, explicitEntry);\n    if (!isInsideDirectory(entryPath, root)) {\n      throw new Error('Plugin entry must be inside the plugin directory');\n    }\n    if (fs.existsSync(entryPath) && fs.statSync(entryPath).isDirectory()) {\n      const nestedEntry = detectEntry(entryPath);\n      return path.relative(root, path.join(entryPath, nestedEntry));\n    }\n    if (path.extname(entryPath) !== '.ts') {\n      throw new Error('Plugin entry must be a .ts file');\n    }\n    if (!fs.existsSync(entryPath) || !fs.statSync(entryPath).isFile()) {\n      throw new Error(`Plugin entry file does not exist: ${explicitEntry}`);\n    }\n    return path.relative(root, entryPath);\n  }\n\n  const manifestPlugin = getSingleManifestPlugin(pluginDir);\n  if (manifestPlugin) {\n    return detectEntry(pluginDir, manifestPlugin.entry);\n  }","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/plugins/install.ts#L138-L174","documentation":"detectEntry validates that an explicitly provided entry file resolves to a path inside the plugin directory. If the resolved entry escapes the plugin root (via `..` or an absolute path outside it), the SDK throws to prevent loading code from arbitrary locations.","triggerScenarios":"Calling entry/detectEntry with an explicitEntry like `../shared/index.ts` or `/etc/something.ts` such that path.resolve(pluginDir, explicitEntry) fails the isInsideDirectory check against the resolved plugin dir.","commonSituations":"Config using `..` to reach shared code outside the plugin; passing an absolute path to a file in another repo; copying a config between projects where the entry now points outside the plugin dir.","solutions":["Move the entry file inside the plugin directory and reference it relatively (e.g. `src/index.ts`).","Remove `..` segments or absolute paths from the explicit entry setting.","Omit the explicit entry and rely on auto-detection if the default candidates apply.","If shared code is needed, publish/import it as a dependency rather than referencing it by path."],"exampleFix":"// before\n{ entry: '../shared/entry.ts' }\n\n// after\n{ entry: 'src/entry.ts' } // file lives inside the plugin dir","handlingStrategy":"validation","validationCode":"import path from 'node:path';\nexport function entryIsInside(pluginDir: string, entry: string): boolean {\n  const root = path.resolve(pluginDir);\n  const resolved = path.resolve(pluginDir, entry);\n  return resolved === root || resolved.startsWith(root + path.sep);\n}\n// call before install: entryIsInside(dir, entry) must be true","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep entries relative to the plugin root; never use `..` or absolute paths in `entry`.","Vendor shared code into the plugin or depend on it as a package instead of path escapes.","Review copied configs for stale out-of-tree entry paths."],"tags":["path-traversal","plugins","configuration","security"],"backgroundTag":"path-outside-allowed-directory","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}