carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

| Previous finding | Round 4 assessment | |---|---| | R1-1: flat tenant borrows a nested socket | Direct connection blocked by §5.4’s cgroup check. | | R1-2: aliases and path routes remain public | Fixed by §5.1’s final-route check. | | R1-3: new box starts public | Fixed by classification before serving and refusal of NULL (§5.1). | | R1-4: revoked grants return after restart | Fixed for retained local state; fresh-box replay remains explicitly accepted (§5.3). | | R1-5: door exceptions fail across routing | Resolved by removing the owner exception and defining the identity transition (§5.4). | | R1-6: socket lifecycle conflicts | Fixed by instance-level listener ownership (§5.4). | | R1-7: transport and body limits | Resolved at spec level (§5.5). | | R2-1: stamp follows serving | Fixed at spec level by the strengthened admission barrier (§5.1). | | R2-2: upgrade serves unclassified engines | Fixed by classification before listeners and refusal of unclassified routes (§5.1). | | R2-3: flat callers borrow door credentials | Direct door attack fixed by the UID restriction (§§5.4, 6.2). | | R2-4: deployment verification fails | Ticket coverage now includes every deploy target (§5.8). A separate expiry problem remains below. | | R2-5: port-80 refusal cannot work remotely | Resolved by the narrowed contract and explicit non-redirecting refusal (§5.1). | | R3-1: previously admitted requests cross the mark | Fixed at spec level: acknowledgement waits for cancellation and completion (§5.1). | | R3-2: flat tenant injects into a nested caller | Partly fixed: §6.2 excludes flat, but its specified predicate misses another unisolated execution class; finding 1 below. | | R3-3: grant-only routes lack watch tickets | Fixed: every deploy target receives a ticket (§5.8). |

Reviewed spec c0d2d531 against locally available amadan origin/main at 512baa59. The implementation files cited below match that revision. No files changed.

  1. P1 — The “all-nested” prerequisite permits unisolated foreign instances (§§5.4, 6.2).

Configure layout intent as nested, with granted nested instance B and ungranted instance A using custom database or socket paths. A classifies as foreign, so the prescribed “no instance route classifies flat” check succeeds and engine sockets open. A can modify B’s environment and plant a library. On B’s next launch, that code runs inside B’s legitimate slice and calls engines as B.

Classify returns foreign for paths outside the two standard layouts (layout.go:103). Start sends that class through the ordinary exec-child path (backend_exec.go:1826), which inherits the edge’s carlos identity and writable /data access (carlos-edge.service:28, backend_exec.go:2236). B’s launch reads its writable environment file (backend_exec.go:2701).

This is concurrent unisolated execution, not the stated residual from a box’s past.

Suggested fix: Base eligibility on exclusion of every unisolated tenant execution path, including LayoutForeign. Require proof of nested isolation for relevant running or launchable instances instead of testing only for absence of LayoutFlat.

  1. P1 — A grant for one engine authorizes a different engine through path routing (§§5.2, 5.4).

Put internal engines A and B in the same account on one box. Register both names, but grant caller C only A. Configure /convert on A’s hostname to target B’s route. C sends POST /convert through its socket with Host: A.

The calling edge checks A’s grant and rewrites the hostname to A’s hostname. Path resolution selects B. Every specified receiving-side check still passes: B is internal, the mark’s engine A names the request hostname, and C has A’s grant. B receives the request despite C having no grant for B.

Existing path reconciliation explicitly permits targets in another app within the same account (aliases.go:395). The edge returns the selected target’s upstream (edge.go:1364). Checking the requested hostname therefore does not bind authorization to the engine route actually dispatched.

Suggested fix: Resolve the registered engine hostname to its primary route identity and require the final upstream to match that identity. Alternatively, bypass path routing for engine calls. Preserve ordinary aliases without allowing a path mapping to widen a grant.

  1. P2 — Watch tickets expire before supported longer deployment watches finish (§5.8).

Run an internal-engine deployment with --timeout 10m. Adoption is delayed, and the target becomes healthy six minutes after promotion. Its ticket expired at five minutes. Every subsequent URL poll receives the internal refusal, so verification fails even though the deployment completed within the requested timeout.

The CLI accepts a configurable watch timeout (deploy.go:75). URL watching uses that timeout as its deadline (deploy.go:1471); the current deploy watcher retains this path for targets without rollout reports (deploywatch.go:295). Section 5.8 specifies one ticket returned with promotion and no renewal mechanism.

Suggested fix: Provide authenticated ticket renewal for the same authorized hostname and version while the watch remains active, with equivalent re-signing in bucket mode.

Overall verdict: reject. The isolation predicate and engine-target authorization still permit calls that the stated identity and grant guarantees forbid.