You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Surfaced by the PR review panel for #1319 (supply-chain-security finding). PR #1319 fixes the visible failure path of #1305 -- when a cross-repo bare repo on a *.ghe.com marketplace fails validation, the install surfaces an actionable host-qualify hint. The panel correctly noted that #1319 deliberately does not address the silent success path of the same syntactic ambiguity.
The gap
The two intents that share the bare cross-repo syntax are:
Intentional cross-host: marketplace on corp.ghe.com, repo: opensource-org/awesome-tool -- author wants the github.com open-source dep.
Misconfigured same-host: marketplace on corp.ghe.com, repo: platform-team/shared-tool -- author wants the corp.ghe.com enterprise dep.
Resolver-level disambiguation is impossible. PR #1319 covers the case where the misconfigured intent's resolution fails validation (because the same owner/repo is not on github.com), but does not cover the case where an attacker pre-stages platform-team/shared-tool on github.com with malicious content:
Operator publishes a *.ghe.com marketplace with repo: platform-team/shared-tool intending the enterprise repo.
Attacker registers platform-team/shared-tool on github.com first (the enterprise org's namespace is observable from public marketplace.json files in many setups).
apm install shared-tool@my-marketplace resolves canonical to bare platform-team/shared-tool/plugins/shared; DependencyReference.parse defaults host to github.com; _validate_package_exists returns True against the attacker-staged repo.
Install succeeds, lockfile records https://github.com/platform-team/shared-tool as the origin, attacker content executes under the operator's APM context.
This is a dependency-confusion-class vector (cf. the npm internal-package-name confusion attacks). Mitigations span resolver + install layers and cannot fit inside #1305's scope without changing the resolver routing PR #1292 deliberately preserved.
The #1305 issue body framed the problem as "the misconfigured case silently 401s with no actionable hint" -- a diagnostic-surface concern, not a security-boundary concern. The panel's supply-chain-security review of #1319 explicitly classified this finding as "out of scope for a PR whose stated goal is 'surface actionable hint at the failure boundary'". The PR's review recommendation was "ship after resolving the logger.warning swap... do not hold this PR on it... open a follow-up issue".
Possible remediations to evaluate
Not a fixed shape -- needs design. Candidates that surfaced during #1319 discussion:
Resolver-time advisory log on the success path when cross_repo_misconfig_risk is non-None AND validation succeeded. Lower severity than the failure-path warning; visible under --verbose only. Trade-off: still some noise on the legitimate cross-host path, but it is gated behind explicit verbosity.
Lockfile annotation noting "resolved against github.com despite *.ghe.com marketplace origin" so apm audit / future drift checks can flag it post-install.
Marketplace publisher-side validation that rejects bare cross-repo repo fields on enterprise marketplaces and requires host qualification (corp.ghe.com/owner/repo or github.com/owner/repo). Breaks existing manifests that rely on the implicit github.com default for cross-host deps -- needs a migration window.
Resolved-host pinning in marketplace.json -- add a host: field at plugin entry level so the resolver does not have to infer. Schema change.
None of these are obviously correct; they trade off compatibility, verbosity, and security boundary location differently.
Test that locks the current sentinel-attach behavior on the cross-repo path: test_cross_repo_locks_known_silent_misroute in tests/integration/test_ghe_marketplace_install_e2e.py
Test that locks the legitimate cross-host no-hint contract: test_legitimate_cross_host_validation_passes_no_hint in the same file
Reproduce (without actual attack)
The success path can be locally reproduced by mocking _validate_package_exists to return True:
# tests/integration/test_ghe_marketplace_install_e2e.py# (the legitimate cross-host case -- same code path attackers would exploit)deftest_legitimate_cross_host_validation_passes_no_hint(self, capsys):
...
withpatch("apm_cli.commands.install._validate_package_exists", return_value=True):
_resolve_package_references(["shared-tool@my-marketplace"], ...)
# No hint, install proceeds. If the validated repo were attacker-staged,# the operator would see no signal at any layer.
Context
Surfaced by the PR review panel for #1319 (supply-chain-security finding). PR #1319 fixes the visible failure path of #1305 -- when a cross-repo bare
repoon a*.ghe.commarketplace fails validation, the install surfaces an actionable host-qualify hint. The panel correctly noted that #1319 deliberately does not address the silent success path of the same syntactic ambiguity.The gap
The two intents that share the bare cross-repo syntax are:
corp.ghe.com,repo: opensource-org/awesome-tool-- author wants the github.com open-source dep.corp.ghe.com,repo: platform-team/shared-tool-- author wants the corp.ghe.com enterprise dep.Resolver-level disambiguation is impossible. PR #1319 covers the case where the misconfigured intent's resolution fails validation (because the same
owner/repois not on github.com), but does not cover the case where an attacker pre-stagesplatform-team/shared-toolon github.com with malicious content:*.ghe.commarketplace withrepo: platform-team/shared-toolintending the enterprise repo.platform-team/shared-toolon github.com first (the enterprise org's namespace is observable from public marketplace.json files in many setups).apm install shared-tool@my-marketplaceresolves canonical to bareplatform-team/shared-tool/plugins/shared;DependencyReference.parsedefaults host togithub.com;_validate_package_existsreturns True against the attacker-staged repo.https://github.com/platform-team/shared-toolas the origin, attacker content executes under the operator's APM context.CrossRepoMisconfigRisksentinel fix: hint to host-qualify cross-repo on *.ghe.com (closes #1305) #1319 attached is consumed only on validation failure; the success path never reaches the hint emission branch.This is a dependency-confusion-class vector (cf. the npm internal-package-name confusion attacks). Mitigations span resolver + install layers and cannot fit inside #1305's scope without changing the resolver routing PR #1292 deliberately preserved.
Why this is not part of #1319
The #1305 issue body framed the problem as "the misconfigured case silently 401s with no actionable hint" -- a diagnostic-surface concern, not a security-boundary concern. The panel's supply-chain-security review of #1319 explicitly classified this finding as "out of scope for a PR whose stated goal is 'surface actionable hint at the failure boundary'". The PR's review recommendation was "ship after resolving the logger.warning swap... do not hold this PR on it... open a follow-up issue".
Possible remediations to evaluate
Not a fixed shape -- needs design. Candidates that surfaced during #1319 discussion:
cross_repo_misconfig_riskis non-None AND validation succeeded. Lower severity than the failure-path warning; visible under--verboseonly. Trade-off: still some noise on the legitimate cross-host path, but it is gated behind explicit verbosity.apm audit/ future drift checks can flag it post-install.repofields on enterprise marketplaces and requires host qualification (corp.ghe.com/owner/repoorgithub.com/owner/repo). Breaks existing manifests that rely on the implicitgithub.comdefault for cross-host deps -- needs a migration window.host:field at plugin entry level so the resolver does not have to infer. Schema change.None of these are obviously correct; they trade off compatibility, verbosity, and security boundary location differently.
Related
test_cross_repo_locks_known_silent_misrouteintests/integration/test_ghe_marketplace_install_e2e.pytest_legitimate_cross_host_validation_passes_no_hintin the same fileReproduce (without actual attack)
The success path can be locally reproduced by mocking
_validate_package_existsto returnTrue: