Skip to content

fix(fleet): take the unauthenticated exec surface off the shared frontend bridge - #434

Merged
Yambr merged 2 commits into
docs/demo-walkthroughfrom
fix/g7-off-the-shared-frontend
Aug 11, 2026
Merged

fix(fleet): take the unauthenticated exec surface off the shared frontend bridge#434
Yambr merged 2 commits into
docs/demo-walkthroughfrom
fix/g7-off-the-shared-frontend

Conversation

@Yambr

@Yambr Yambr commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Corrects #433, which I merged on a false premise.

What was wrong

That waiver said the visualiser is "reachable from the host loopback alone — never from the fleet network". The first clause is true; the second was false. The ports: publish is 127.0.0.1:8099:8099, but the service sat on ocu-frontend — a plain bridge (driver: bridge, no internal: true) shared with open-webui, webui, embed-portal, admin and mcp-gateway. A published port governs host exposure, not in-network reachability, so every co-tenant could reach it.

Why that mattered

route takes a credential? what it does
/api/create no creates a real gVisor session
/api/exec no runs an arbitrary argv in the live guest
/api/tool no bash / create_file / str_replace in the guest
/api/destroy no destroys sessions

There is no Authorization check, no token, no header check anywhere on the inbound side — I grepped for all of them. The process holds the gateway mTLS client cert (/pki/client.pem), so any co-tenant could POST an arbitrary argv in cleartext and have it executed under that cert with no credential of its own. open-webui processes untrusted agent and user input and was one of those co-tenants.

The fix

g7 moves to a dedicated ocu-g7 bridge shared with control alone — the only hop it needs (GATEWAY_URL defaults to https://control:9466). The web tier can no longer address it at all.

The use-tls waiver stays, because the rule still cannot see a deployment, but its stated reason is replaced: the containment is the network isolation, and the exposure on this hop is authorisation, not eavesdropping. TLS here would encrypt a channel whose problem was never confidentiality.

Enforced, not asserted

deploy/tests/test_fleet_g7_isolation.py makes all three properties mechanical, which is what #433 was missing — it asserted a precondition nothing checked:

  • the published port keeps its 127.0.0.1: prefix
  • g7 shares no bridge with any web-tier service
  • g7 still shares a network with control — so the isolation cannot pass by breaking the service

Mutation-checked: each reds on its own violation (put g7 back on ocu-frontend; drop the loopback prefix; remove control from ocu-g7).

Not addressed here

The /api/* surface is still unauthenticated. Network isolation contains it for this deployment; it is not a substitute for an inbound credential. That is a larger change than this correction, and it belongs to whoever owns the demo surface.

…tend bridge

The waiver merged in #433 rested on a false premise. It said the visualiser was
"reachable from the host loopback alone — never from the fleet network". The
`ports:` publish is loopback, but the service sat on `ocu-frontend`, a plain
bridge it shared with open-webui, webui, embed-portal, admin and mcp-gateway. A
published port says nothing about in-network callers, so every one of those
could reach it.

What they could reach matters: `/api/create`, `/api/exec`, `/api/tool` and
`/api/destroy` take NO inbound credential, and the process holds the gateway
mTLS client cert. Any co-tenant could POST an arbitrary argv in cleartext and
have it executed in a live guest under that cert — with open-webui, which
processes untrusted input, among the co-tenants.

g7 now shares a dedicated bridge with control alone, which is the only hop it
needs. The waiver stays, because the rule still cannot see a deployment, but it
now states the containment that is real instead of the one that was not, and
says that the exposure here is authorisation rather than eavesdropping.

`deploy/tests/test_fleet_g7_isolation.py` turns all of it into properties: the
loopback prefix, no shared bridge with the web tier, and — so the isolation
cannot pass by breaking the service — that g7 still shares a network with
control. Mutation-checked: each of the three reds on its own violation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (2)
  • main
  • next/v1

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c04fa586-f63e-47b1-9f06-898fca888717

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

… tier

A hard-coded list of web-tier names passes silently the moment a service is
renamed or a new one is added — the assertion would still be green while the
containment was gone. The test now derives the actual co-tenant set from the
compose file and requires it to be exactly `{control}`, so any unlisted service
joining that bridge reds and is named in the failure.

Mutation-checked: adding an arbitrary service to `ocu-g7` reds and prints which
one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Yambr
Yambr merged commit 5f66495 into docs/demo-walkthrough Aug 11, 2026
11 checks passed
@Yambr
Yambr deleted the fix/g7-off-the-shared-frontend branch August 11, 2026 09:54
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.

2 participants