[security] Use-only lease shares can attach forged runs to the lease owner's history
Summary
Crabbox's coordinator lets a user with only use access to another owner's lease create a run record that is attributed to that victim-owned lease. POST /v1/runs accepts a supplied leaseID when the lease is merely visible to the requester, and visibility includes use shares. The same creation path then records the victim owner in run.leaseOwners, while the attacker remains the run owner and can write events and retained logs to that run.
This crosses a supported Crabbox boundary because the maintainer-authored security policy treats access to another owner's resources contrary to documented authorization as in scope. The finding does not depend on hostile tenants sharing one broker as a generic isolation claim; it depends on a lower-privileged, authenticated share recipient mutating coordinator-managed run history that becomes readable as part of the lease owner's resource state.
Affected Components
- Verified target commit:
fca333101f70f3bb14f3368af74b787f83e7aa17
- Component: coordinator run creation, run attribution, run readability, and portal run history
- Relevant files:
worker/src/fleet.ts
worker/src/portal.ts
Attack Path
Attacker role:
An authenticated user token whose principal has use access, but not manage or owner access, to a victim-owned lease.
Prerequisites:
- The victim owner or org shares a lease with the attacker using role
use.
- The attacker can call the coordinator run API with their own authenticated user token.
- The victim later views the lease page, run detail page, raw logs, or run event JSON.
Steps:
- The attacker sends
POST /v1/runs with the victim lease id in leaseID and attacker-chosen run metadata such as label and command.
createRun loads the lease and rejects only if leaseVisibleToRequest is false. leaseVisibleToRequest is backed by leaseAccessRole, and leaseAccessRoleForPrincipal returns use for user or org use shares.
createRun stores the new run under the attacker's owner and org, then calls setRunLeaseAttribution, which adds the victim lease owner to run.leaseOwners.
- Because the attacker owns the run,
runWritableByRequest permits them to post run events and finish the run with attacker-controlled retained log content.
- Because the victim owner is listed in
run.leaseOwners, runReadableToRequest permits the victim to read the attacker-owned run.
- The victim's lease detail page filters all runs for those that reference the lease and are readable to the victim, so the forged run appears in the lease's recent-run table. The victim can then open the run detail page, raw logs, and event JSON for attacker-controlled content.
Expected behavior:
Use-only access can intentionally permit operating a shared lease, but it should not let the use-share recipient bind arbitrary coordinator run records, events, and retained logs into the lease owner's trusted run history. Run-to-lease attribution should require owner or manage access, or use-share-created runs should remain readable only to the run owner unless an owner/manage principal creates or approves the attribution.
Impact
A lower-privileged share recipient can inject arbitrary run records into another owner's lease history. The injected run can contain attacker-controlled command strings, run labels, events, finish metadata, and retained raw logs, and the victim owner is authorized to retrieve those records through normal coordinator and portal paths.
The reviewed portal rendering escapes HTML, so this is not an XSS finding. The impact is cross-owner integrity of coordinator-managed operational evidence: a use-share principal can pollute another owner's run ledger and make forged execution evidence appear attached to the victim lease. That can mislead debugging, release evidence, incident review, billing review, or other workflows that treat the lease run history as owner-associated state.
Severity Assessment
CVSS Assessment
| Metric |
v3.1 |
v4.0 |
| Score |
4.3 / 10.0 |
5.3 / 10.0 |
| Severity |
Medium |
Medium |
| Vector |
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N |
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N |
| Calculator |
CVSS v3.1 Calculator |
CVSS v4.0 Calculator |
The score reflects a network-reachable authenticated attacker with low privileges and no victim interaction needed to create and populate the forged run. The direct demonstrated impact is limited integrity loss in the victim owner's coordinator run history. Confidentiality and availability are not scored because the attacker is supplying the log/event data rather than reading victim secret data or disrupting service.
Recommended Remediation
Use the same authorization boundary for run-to-lease attribution that Crabbox uses for lease management. A small fix is to require leaseManageableByRequest when createRun receives a leaseID, and to apply the same owner/manage check before POST /v1/runs/:id/events accepts an event leaseID that changes or expands run attribution.
If use-share users must be able to start commands against shared leases, keep those run records scoped to the run owner unless an owner or manage principal explicitly creates or approves lease-owner attribution. Add regression coverage for both creation-time attribution and event-time attribution.
Validation
Validation method:
Source review of the isolated target copy at commit fca333101f70f3bb14f3368af74b787f83e7aa17.
Positive evidence:
worker/src/fleet.ts:852-853 routes POST /v1/runs to createRun.
worker/src/fleet.ts:8840-8850 parses leaseID, loads the lease, and rejects only when leaseVisibleToRequest is false.
worker/src/fleet.ts:10455-10457 defines visibility as any non-empty leaseAccessRole.
worker/src/fleet.ts:10496-10512 returns use when the principal has a user or org use share.
worker/src/fleet.ts:8853-8859 creates the run owned by the attacker principal from the request, with an initially empty leaseOwners list.
worker/src/fleet.ts:8873-8875 calls setRunLeaseAttribution for the visible lease.
worker/src/fleet.ts:10554-10564 records the lease id and the lease owner's { owner, org } in the run attribution.
worker/src/fleet.ts:10515-10519 makes the attacker-owned run writable by the attacker.
worker/src/fleet.ts:8935-8948 lets a writable run owner append events, and worker/src/fleet.ts:8974-9022 lets a writable run owner finish the run and write retained log content.
worker/src/fleet.ts:10522-10533 grants read access to principals listed in run.leaseOwners.
worker/src/fleet.ts:5088-5108 builds a lease detail page from runs that reference the lease and pass runReadableToRequest.
worker/src/fleet.ts:5666-5696 serves portal run detail, raw logs, and event JSON to readable principals.
worker/src/portal.ts:498-615, worker/src/portal.ts:887-1008, and worker/src/portal.ts:2481-2502 render the recent-run table, run detail, log tail, and events.
Counterevidence reviewed:
worker/src/portal.ts escapes run labels, commands, logs, and event fields before HTML rendering, so the validated issue is not browser script execution.
runWritableByRequest still restricts event and finish writes to the run owner or admin. The issue is the earlier authorization mismatch that lets a use-share user become the run owner while attributing the run to the victim's lease.
- Crabbox's security policy explicitly excludes mutually adversarial tenants as a general isolation model, but this specific path is in scope because the coordinator has documented owner/share roles and the lower-privileged
use role can write state into another owner's resource history.
Suggested regression coverage:
- Add a coordinator route test that creates a victim-owned lease shared to an attacker with role
use, authenticates as the attacker, and asserts POST /v1/runs with the victim lease id is rejected or does not add the victim to run.leaseOwners.
- Add a second test where an attacker-owned run attempts to append an event with a visible victim lease id and assert that owner/manage access is required for new lease attribution.
- Verify that legitimate owner or
manage principals can still create or attribute runs to the lease.
Suggested verification command:
[security] Use-only lease shares can attach forged runs to the lease owner's history
Summary
Crabbox's coordinator lets a user with only
useaccess to another owner's lease create a run record that is attributed to that victim-owned lease.POST /v1/runsaccepts a suppliedleaseIDwhen the lease is merely visible to the requester, and visibility includesuseshares. The same creation path then records the victim owner inrun.leaseOwners, while the attacker remains the run owner and can write events and retained logs to that run.This crosses a supported Crabbox boundary because the maintainer-authored security policy treats access to another owner's resources contrary to documented authorization as in scope. The finding does not depend on hostile tenants sharing one broker as a generic isolation claim; it depends on a lower-privileged, authenticated share recipient mutating coordinator-managed run history that becomes readable as part of the lease owner's resource state.
Affected Components
fca333101f70f3bb14f3368af74b787f83e7aa17worker/src/fleet.tsworker/src/portal.tsAttack Path
Attacker role:
An authenticated user token whose principal has
useaccess, but notmanageor owner access, to a victim-owned lease.Prerequisites:
use.Steps:
POST /v1/runswith the victim lease id inleaseIDand attacker-chosen run metadata such aslabelandcommand.createRunloads the lease and rejects only ifleaseVisibleToRequestis false.leaseVisibleToRequestis backed byleaseAccessRole, andleaseAccessRoleForPrincipalreturnsusefor user or orguseshares.createRunstores the new run under the attacker'sownerandorg, then callssetRunLeaseAttribution, which adds the victim lease owner torun.leaseOwners.runWritableByRequestpermits them to post run events and finish the run with attacker-controlled retained log content.run.leaseOwners,runReadableToRequestpermits the victim to read the attacker-owned run.Expected behavior:
Use-only access can intentionally permit operating a shared lease, but it should not let the use-share recipient bind arbitrary coordinator run records, events, and retained logs into the lease owner's trusted run history. Run-to-lease attribution should require owner or
manageaccess, or use-share-created runs should remain readable only to the run owner unless an owner/manage principal creates or approves the attribution.Impact
A lower-privileged share recipient can inject arbitrary run records into another owner's lease history. The injected run can contain attacker-controlled command strings, run labels, events, finish metadata, and retained raw logs, and the victim owner is authorized to retrieve those records through normal coordinator and portal paths.
The reviewed portal rendering escapes HTML, so this is not an XSS finding. The impact is cross-owner integrity of coordinator-managed operational evidence: a use-share principal can pollute another owner's run ledger and make forged execution evidence appear attached to the victim lease. That can mislead debugging, release evidence, incident review, billing review, or other workflows that treat the lease run history as owner-associated state.
Severity Assessment
CVSS Assessment
The score reflects a network-reachable authenticated attacker with low privileges and no victim interaction needed to create and populate the forged run. The direct demonstrated impact is limited integrity loss in the victim owner's coordinator run history. Confidentiality and availability are not scored because the attacker is supplying the log/event data rather than reading victim secret data or disrupting service.
Recommended Remediation
Use the same authorization boundary for run-to-lease attribution that Crabbox uses for lease management. A small fix is to require
leaseManageableByRequestwhencreateRunreceives aleaseID, and to apply the same owner/manage check beforePOST /v1/runs/:id/eventsaccepts an eventleaseIDthat changes or expands run attribution.If use-share users must be able to start commands against shared leases, keep those run records scoped to the run owner unless an owner or manage principal explicitly creates or approves lease-owner attribution. Add regression coverage for both creation-time attribution and event-time attribution.
Validation
Validation method:
Source review of the isolated target copy at commit
fca333101f70f3bb14f3368af74b787f83e7aa17.Positive evidence:
worker/src/fleet.ts:852-853routesPOST /v1/runstocreateRun.worker/src/fleet.ts:8840-8850parsesleaseID, loads the lease, and rejects only whenleaseVisibleToRequestis false.worker/src/fleet.ts:10455-10457defines visibility as any non-emptyleaseAccessRole.worker/src/fleet.ts:10496-10512returnsusewhen the principal has a user or orguseshare.worker/src/fleet.ts:8853-8859creates the run owned by the attacker principal from the request, with an initially emptyleaseOwnerslist.worker/src/fleet.ts:8873-8875callssetRunLeaseAttributionfor the visible lease.worker/src/fleet.ts:10554-10564records the lease id and the lease owner's{ owner, org }in the run attribution.worker/src/fleet.ts:10515-10519makes the attacker-owned run writable by the attacker.worker/src/fleet.ts:8935-8948lets a writable run owner append events, andworker/src/fleet.ts:8974-9022lets a writable run owner finish the run and write retained log content.worker/src/fleet.ts:10522-10533grants read access to principals listed inrun.leaseOwners.worker/src/fleet.ts:5088-5108builds a lease detail page from runs that reference the lease and passrunReadableToRequest.worker/src/fleet.ts:5666-5696serves portal run detail, raw logs, and event JSON to readable principals.worker/src/portal.ts:498-615,worker/src/portal.ts:887-1008, andworker/src/portal.ts:2481-2502render the recent-run table, run detail, log tail, and events.Counterevidence reviewed:
worker/src/portal.tsescapes run labels, commands, logs, and event fields before HTML rendering, so the validated issue is not browser script execution.runWritableByRequeststill restricts event and finish writes to the run owner or admin. The issue is the earlier authorization mismatch that lets a use-share user become the run owner while attributing the run to the victim's lease.userole can write state into another owner's resource history.Suggested regression coverage:
use, authenticates as the attacker, and assertsPOST /v1/runswith the victim lease id is rejected or does not add the victim torun.leaseOwners.manageprincipals can still create or attribute runs to the lease.Suggested verification command:
npm test --prefix worker