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
+8 -10
View File
@@ -40,7 +40,6 @@ use crate::marketplace::home_dir;
use crate::marketplace::list_marketplaces_with_home;
use crate::marketplace::plugin_interface_with_marketplace_category;
use crate::marketplace_policy::MarketplacePolicy;
use crate::marketplace_policy::allowed_configured_marketplace_names;
use crate::marketplace_policy::configured_plugins_from_stack;
use crate::marketplace_upgrade::ConfiguredMarketplaceUpgradeError;
use crate::marketplace_upgrade::ConfiguredMarketplaceUpgradeOutcome;
@@ -2921,16 +2920,15 @@ impl PluginsManager {
) -> Result<MarketplaceListOutcome, MarketplaceError> {
let mut outcome = list_marketplaces_with_home(roots, home_dir().as_deref())?;
let policy = MarketplacePolicy::from_requirements(config.config_layer_stack.requirements());
if !policy.is_restricted() {
return Ok(outcome);
}
let allowed_marketplace_names = allowed_configured_marketplace_names(
&config.config_layer_stack,
self.codex_home.as_path(),
);
outcome.marketplaces.retain(|marketplace| {
is_openai_curated_marketplace_name(&marketplace.name)
|| allowed_marketplace_names.contains(&marketplace.name)
policy
.validate_install(
&config.config_layer_stack,
self.codex_home.as_path(),
&marketplace.path,
&marketplace.name,
)
.is_ok()
});
Ok(outcome)
}