Prevent marketplace identity spoofing (#39165)

## Why

Repository manifests and user-configured sources must not be able to claim names reserved for managed or remote marketplaces.

## What changed

- Reject reserved marketplace names from unmanaged sources during discovery, installation, configuration projection, and configured marketplace upgrades, even when source restrictions are disabled.
- Recognize managed marketplaces only at their expected paths. Preserve the required macOS and Windows path equivalences without allowing symlink aliases to inherit managed provenance.

## Testing

- Cover reserved-name rejection for plugin list and install RPCs, configured upgrades, unrestricted policy, and remote marketplace names.
- Cover symlink spoofing and Windows managed-path normalization.

GitOrigin-RevId: a610bdc382857f306dd3e244f0992de2ec279673
This commit is contained in:
Eric Traut
2026-08-18 07:56:41 +00:00
committed by copyberry
parent e2eea07140
commit 0acf302db5
7 changed files with 262 additions and 65 deletions
@@ -156,9 +156,9 @@ async fn omits_openai_curated_but_keeps_configured_marketplaces_for_remote_codex
write_openai_curated_marketplace(&curated_root, &["slack"]);
let bundled_marketplace_name = OPENAI_BUNDLED_MARKETPLACE_NAME;
let bundled_marketplace_root = codex_home
.path()
.join(format!(".tmp/marketplaces/{bundled_marketplace_name}"));
let bundled_marketplace_root = codex_home.path().join(format!(
".tmp/bundled-marketplaces/{bundled_marketplace_name}"
));
write_file(
&bundled_marketplace_root.join(".agents/plugins/marketplace.json"),
&format!(
@@ -179,8 +179,8 @@ async fn omits_openai_curated_but_keeps_configured_marketplaces_for_remote_codex
plugins = true
[marketplaces.{bundled_marketplace_name}]
source_type = "git"
source = "/tmp/{bundled_marketplace_name}"
source_type = "local"
source = {bundled_marketplace_root:?}
"#
),
);
@@ -240,7 +240,7 @@ async fn deduplicates_and_reprojects_cached_configured_marketplace_plugin() {
let plugin_id = format!("{plugin_name}@{marketplace_name}");
let marketplace_root = codex_home
.path()
.join(format!(".tmp/marketplaces/{marketplace_name}"));
.join(format!(".tmp/bundled-marketplaces/{marketplace_name}"));
write_file(
&marketplace_root.join(".agents/plugins/marketplace.json"),
&format!(
@@ -267,8 +267,8 @@ async fn deduplicates_and_reprojects_cached_configured_marketplace_plugin() {
plugins = true
[marketplaces.{marketplace_name}]
source_type = "git"
source = "/tmp/{marketplace_name}"
source_type = "local"
source = {marketplace_root:?}
"#
),
);