{"record":{"id":"1b36d4d1b148a490","repo":"paperclipai/paperclip","slug":"npm-installs-are-disabled-on-cloud-managed-instanc","errorCode":null,"errorMessage":"npm installs are disabled on cloud-managed instances; only plugins bundled with the application may be installed","messagePattern":"npm installs are disabled on cloud-managed instances; only plugins bundled with the application may be installed","errorType":"http","errorClass":null,"httpStatus":403,"severity":"error","filePath":"server/src/routes/plugins.ts","lineNumber":1179,"sourceCode":"\n    // Validate package name format\n    const trimmedPackage = packageName.trim();\n    if (trimmedPackage.length === 0) {\n      res.status(400).json({ error: \"packageName cannot be empty\" });\n      return;\n    }\n\n    // Basic security check for package name (prevent injection)\n    if (!isLocalPath && /[<>:\"|?*]/.test(trimmedPackage)) {\n      res.status(400).json({ error: \"packageName contains invalid characters\" });\n      return;\n    }\n\n    // Cloud install floor: on harness-managed instances only bundled-catalog\n    // sources are installable, regardless of actor privileges or flag state.\n    const cloudManaged = isCloudManagedInstance();\n    if (cloudManaged && !isLocalPath) {\n      res.status(403).json({\n        error:\n          \"npm installs are disabled on cloud-managed instances; only plugins bundled with the application may be installed\",\n      });\n      return;\n    }\n\n    // Canonicalize local install paths on every instance so traversal\n    // segments and symlinks cannot smuggle an aliased path past validation.\n    let canonicalLocalPath: string | undefined;\n    if (isLocalPath) {\n      const validated = await canonicalizeLocalPluginPath(trimmedPackage);\n      if (!validated.ok) {\n        res.status(400).json({ error: `Invalid localPath: ${validated.reason}` });\n        return;\n      }\n      if (cloudManaged && !(await isWithinBundledPluginRoot(validated.canonicalPath))) {\n        res.status(403).json({\n          error:","sourceCodeStart":1161,"sourceCodeEnd":1197,"githubUrl":"https://github.com/paperclipai/paperclip/blob/a7e689b3c35347b529cb9f54c9b9a8575a3dcab6/server/src/routes/plugins.ts#L1161-L1197","documentation":"403 policy guard on POST /plugins/install. Fires on cloud-managed instances when the requested install source is not a local path (i.e. an npm/registry install); only plugins bundled with the application may be installed there, regardless of privileges.","triggerScenarios":"Thrown at server/src/routes/plugins.ts:1163 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["This is an authorization rule, not a bug: perform the action with an actor that satisfies the stated constraint (board user, the owning agent, or an in-scope resource).","If access should be allowed, verify the actor's credentials/company scope and the resource's ownership before retrying."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"a7e689b3c35347b529cb9f54c9b9a8575a3dcab6","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}