{"record":{"id":"1d98d6e314fb98b8","repo":"google-gemini/gemini-cli","slug":"installing-extension-from-source-installmetadat","errorCode":null,"errorMessage":"Installing extension from source \"${installMetadata.source}\" is not allowed by the \"allowedExtensions\" security setting.","messagePattern":"Installing extension from source \"(.+?)\" is not allowed by the \"allowedExtensions\" security setting\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/config/extension-manager.ts","lineNumber":200,"sourceCode":"    previousExtensionConfig?: ExtensionConfig,\n    requestConsentOverride?: (consent: string) => Promise<boolean>,\n  ): Promise<GeminiCLIExtension> {\n    if ((this.settings.security?.allowedExtensions?.length ?? 0) > 0) {\n      const extensionAllowed = this.settings.security?.allowedExtensions.some(\n        (pattern) => {\n          try {\n            return new RegExp(pattern).test(\n              getRealPath(installMetadata.source),\n            );\n          } catch (e) {\n            throw new Error(\n              `Invalid regex pattern in allowedExtensions setting: \"${pattern}. Error: ${getErrorMessage(e)}`,\n            );\n          }\n        },\n      );\n      if (!extensionAllowed) {\n        throw new Error(\n          `Installing extension from source \"${installMetadata.source}\" is not allowed by the \"allowedExtensions\" security setting.`,\n        );\n      }\n    } else if (\n      (installMetadata.type === 'git' ||\n        installMetadata.type === 'github-release') &&\n      this.settings.security.blockGitExtensions\n    ) {\n      throw new Error(\n        'Installing extensions from remote sources is disallowed by your current settings.',\n      );\n    }\n\n    const isUpdate = !!previousExtensionConfig;\n    let newExtensionConfig: ExtensionConfig | null = null;\n    let localSourcePath: string | undefined;\n    let extension: GeminiCLIExtension | null;\n    try {","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/cli/src/config/extension-manager.ts#L182-L218","documentation":"Thrown when `settings.security.allowedExtensions` is a non-empty array but no pattern in it matches the resolved real path of `installMetadata.source`. The allowlist is opt-in: once you populate it, every extension source must match at least one pattern or the install is refused.","triggerScenarios":"Attempting to install from a new GitHub org or local path that isn't covered by any of the configured patterns; the allowlist was tightened and a previously-allowed source no longer matches.","commonSituations":"Locking down to `^https://github\\..com/myorg/` and then trying to install a third-party extension; pointing at a local dev directory that the patterns don't cover; migrating machines where the home directory path changes and breaks absolute-path patterns.","solutions":["Add a regex pattern that matches the source you want to install into `security.allowedExtensions`.","Use a broader prefix pattern such as `^https://github\\.com/` if multiple orgs are allowed.","Verify the resolved path with `realpath`/`getRealPath` — relative sources are resolved against `workspaceDir`."],"exampleFix":"// before\n{ \"security\": { \"allowedExtensions\": [\"^https://github\\\\.com/myorg/\"] } }\n// after\n{ \"security\": { \"allowedExtensions\": [\"^https://github\\\\.com/(myorg|trusted-partner)/\"] } }","handlingStrategy":"validation","validationCode":"function isSourceAllowed(source: string, patterns: RegExp[]): boolean {\n  const real = getRealPath(source);\n  return patterns.some((re) => re.test(real));\n}\nconst patterns = (settings.security?.allowedExtensions ?? []).map((p) => new RegExp(p));\nif (patterns.length > 0 && !isSourceAllowed(installMetadata.source, patterns)) {\n  throw new Error(`Source ${installMetadata.source} not in allowedExtensions.`);\n}","typeGuard":"function sourceMatchesAllowed(source: string, patterns: readonly string[]): boolean {\n  const real = getRealPath(source);\n  return patterns.some((p) => { try { return new RegExp(p).test(real); } catch { return false; } });\n}","tryCatchPattern":null,"preventionTips":["Design allowlist patterns around the resolved real path, not the raw source.","Use anchored prefixes (`^https://github.com/myorg/`) to avoid accidental matches.","Re-test the allowlist whenever you add a new trusted org."],"tags":["extensions","security","allowed-extensions","policy"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}