Skip to content

fix(x402): inject agent upstream auth + close cross-namespace agent.ref gap#566

Open
bussyjd wants to merge 4 commits into
mainfrom
release/v0.10.0-rc8
Open

fix(x402): inject agent upstream auth + close cross-namespace agent.ref gap#566
bussyjd wants to merge 4 commits into
mainfrom
release/v0.10.0-rc8

Conversation

@bussyjd
Copy link
Copy Markdown
Collaborator

@bussyjd bussyjd commented May 28, 2026

Aggregates the two follow-up x402 agent fixes on top of v0.10.0-rc7 (already merged to main via #565).

What's included

Commit Source PR Summary
1c990b3 #564 (was: fix/agent-ref-namespace-confused-deputy) Reject spec.agent.ref.namespace != metadata.namespace at the controller boundary. Fail-closed, single-line invariant.
f4bd11f #556 (was: fix/agent-seller-upstream-auth) Inject Authorization: Bearer <API_SERVER_KEY> into agent-route upstream after x402 verification. Fixes 401 on obol sell agent paid path.

Both source PRs are closed in favour of this aggregate. Their full discussion threads live there and remain linked from the closing comments.

Review context (carried over from #556 + #564)

  • fix(x402): inject agent upstream auth #556 was approved by @OisinKyne with a parking-lot question: "can ServiceOffer leak the API_SERVER_KEY value to a buyer?" Full analysis in #556's comment thread — short version: literal-value leak is fine (UpstreamURL is controller-derived from in-cluster Hermes Service DNS; verifier proxies via httputil.ReverseProxy and never echoes Authorization), but the analysis surfaced a latent confused-deputy issue: resolveAgentOffer didn't enforce that spec.agent.ref.namespace matched the offer namespace, so a principal with namespace-scoped serviceoffers write could publish an offer pointing agent.ref at another tenant's Agent, get the route published with the victim's bearer, and serve as an x402-gated proxy into the victim Hermes /api/*.
  • security(controller): reject cross-namespace spec.agent.ref #564 is the fail-closed guard for that gap. Not exploitable in today's single-Hermes-mother layout (only one principal has serviceoffers write, and it already has cluster-wide write over its children), but becomes exploitable the moment sub-agent SAs split out or multi-mother marketplace mode lands.

Validation

  • go build ./... clean on release/v0.10.0-rc8.
  • go vet ./... clean (pre-existing unsafe.Pointer warnings in internal/enclave/enclave_darwin.go unrelated to these changes).
  • flows/release-smoke.sh ran 13/13 PASS on v0.10.0-rc7 (the base of this branch) against qwen36-deep on a Spark2 vLLM endpoint. The two follow-up commits don't change runtime payment plumbing — they only constrain controller acceptance — so the green smoke is the relevant gate.

Test plan

go test ./internal/serviceoffercontroller/... ./internal/x402/... -count=1

New regressions covered by #564's commit: TestResolveAgentOffer_RejectsCrossNamespaceRef + serviceoffer_source route-zero assertion when ref mismatches. Existing happy-path tests updated to set metadata.namespace so they exercise the post-guard codepath.

bussyjd and others added 4 commits May 27, 2026 15:02
resolveAgentOffer accepted any ref.Namespace, while the verifier route
source in PR #556 keys the hermes-api-server API_SERVER_KEY lookup off
offer.Spec.Agent.Ref.Namespace. Combined with the cluster-wide
openclaw-monetize-write ClusterRoleBinding, any principal holding the
Hermes obol-agent SA token could publish a ServiceOffer in their own
namespace referencing another tenant's Agent, causing the verifier to
inject the victim's API_SERVER_KEY as upstream Authorization on a route
under attacker-controlled path and payTo. Paying buyers would gain
authenticated proxy access to the victim Hermes /api/* (chat, skills,
sub-agent management, wallet ops).

Fail-closed in the controller before any route is published or any
bearer is resolved. The legitimate flow (mother creates offer in the
agent's own namespace) is preserved.

Flagged on PR #556 by @OisinKyne; not exploitable in today's single-
mother layout, but lands ahead of sub-agent SA split / multi-mother
marketplace mode.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant