Skip to content

[security] AWS direct stop can terminate non-Crabbox EC2 instances by raw instance ID #703

Description

@coygeek

[security] AWS direct stop can terminate non-Crabbox EC2 instances by raw instance ID

Summary

The direct AWS provider accepts a raw EC2 instance ID in crabbox stop --provider aws --id i-..., resolves it with DescribeInstances, and passes the described instance into the release path without verifying that it is a Crabbox-owned lease. A local operator or automation path that can invoke Crabbox with configured AWS credentials can therefore make Crabbox call TerminateInstances for any describable instance in the configured AWS account/region set, including instances that lack the canonical crabbox=true, created_by=crabbox, provider=aws, lease, and slug tags.

This is in scope under the maintainer-authored SECURITY.md boundary because the policy explicitly calls out destructive provider actions against resources Crabbox cannot strongly identify as its own. It does not depend on hostile multi-tenant isolation; the crossed boundary is Crabbox's provider-resource ownership check before a destructive cloud API call.

Affected Components

  • Checked commit: 6dba4afd1c5a4be0a780cf035d1b397e8982d478
  • Component: CLI direct AWS provider lifecycle
  • Affected files and lines:
    • internal/cli/run.go:2914-3105
    • internal/providers/aws/backend.go:129-149
    • internal/providers/aws/backend.go:200-208
    • internal/providers/aws/backend.go:347-359
    • internal/cli/aws.go:595-615
    • internal/cli/provider_backend.go:680-682

Attack Path

Attacker role:

local operator or local automation with access to configured AWS provider credentials

Prerequisites:

  • The local Crabbox configuration selects provider=aws or the caller supplies --provider aws.
  • The configured AWS credentials can describe and terminate a target EC2 instance.
  • The caller knows or can guess a target EC2 instance ID in the configured AWS region set.
  • No internal controller expected-identity flags are supplied; ordinary CLI stop leaves the expected identity empty, so the generic identity validator does not enforce an immutable lease/resource match.

Steps:

  1. Choose an EC2 instance ID that is not a Crabbox lease and does not carry Crabbox ownership tags.
  2. Run crabbox stop --provider aws --id i-0123456789abcdef0 from a local checkout or automation context using the configured AWS credentials.
  3. App.stop resolves the ID with ReleaseOnly: true; because no internal expected identity flags were supplied, ValidateLeaseTargetProviderIdentity returns without checking the resolved target.
  4. The AWS backend raw-ID branch calls GetServer for the i-* ID and returns the described server without checking Crabbox ownership tags, lease ID shape, slug, or name.
  5. ReleaseLease calls deleteServer, which calls AWSClient.DeleteServer, issuing TerminateInstances for the raw instance ID.

Expected result:

Crabbox terminates an EC2 instance that it cannot strongly identify as a Crabbox-owned lease.

Control/dataflow:

local --id i-* argument
  -> App.stop ResolveRequest{ReleaseOnly: true}
  -> awsLeaseBackend.Resolve raw i-* branch
  -> AWSClient.GetServer without Crabbox tag filter
  -> awsLeaseBackend.ReleaseLease/deleteServer without ownership validation
  -> AWSClient.DeleteServer / EC2 TerminateInstances
  -> non-Crabbox EC2 instance deletion

Impact

This crosses the documented provider-resource safety boundary: Crabbox can perform a destructive provider action against a cloud resource it cannot strongly identify as its own. In an AWS account that mixes Crabbox leases with unrelated EC2 workloads, an operator mistake, malicious local automation, or a compromised local workflow using Crabbox's configured provider route can terminate non-Crabbox instances. The direct AWS inventory cleanup path is narrower because it lists only instances with tag:crabbox=true, while the raw-ID stop path bypasses that inventory filter and has no equivalent release-time ownership gate.

Severity Assessment

CVSS Assessment

Metric v3.1 v4.0
Score 5.5 / 10.0 6.8 / 10.0
Severity Medium Medium
Vector CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Calculator CVSS v3.1 Calculator CVSS v4.0 Calculator

The attack is local and requires a caller that can use the configured AWS route, so this is not a remote authentication bypass. The impact is high availability loss for the victim EC2 instance because Crabbox reaches a provider termination API without first proving the resource belongs to a Crabbox lease. Confidentiality and integrity are not directly affected by the observed path.

Recommended Remediation

Add a shared AWS ownership validation gate before any destructive AWS direct-provider operation. The gate should reject a server unless it has a canonical Crabbox lease identity: crabbox=true, created_by=crabbox, provider=aws, a valid lease id, a non-empty slug, and preferably the expected Name or provider-key relationship used by created leases. Apply it in both the raw i-* resolve branch when ReleaseOnly is true and in deleteServer as defense in depth. If raw EC2 IDs are intentionally supported for adoption or manual cleanup, require an explicit adoption flow that verifies and writes Crabbox ownership metadata before allowing release.

Validation

Validation method:

source review with local CVSS scoring

Evidence and counterevidence:

  • internal/cli/run.go:3067-3093 resolves the user-supplied ID with ReleaseOnly: true, then calls ReleaseLease; ValidateLeaseTargetProviderIdentity is a no-op when no internal expected identity flags were provided.
  • internal/providers/aws/backend.go:129-149 has a raw i-* branch that calls GetServer and returns a LeaseTarget without checking crabbox, created_by, provider, lease ID shape, slug, or name.
  • internal/cli/aws.go:595-605 implements GetServer with DescribeInstances by instance ID, unlike ListCrabboxServers in internal/cli/aws.go:147-152, which filters on tag:crabbox=true.
  • internal/providers/aws/backend.go:200-208 calls deleteServer from ReleaseLease, and internal/providers/aws/backend.go:347-359 calls client.DeleteServer without an AWS ownership check.
  • internal/cli/aws.go:610-615 maps DeleteServer to EC2 TerminateInstances.
  • internal/cli/provider_labels.go:10-31 shows the canonical tags Crabbox-created direct leases receive, and internal/cli/aws.go:1112-1129 shows that arbitrary EC2 tags are copied into the Server.Labels map returned by GetServer.
  • Counterevidence considered: direct AWS cleanup uses ListCrabboxServers, and adjacent providers such as Hetzner and GCP have explicit ownership or canonical-label gates before destructive paths. Those controls do not protect the raw AWS stop path.

Suggested regression coverage or verification:

  • internal/providers/aws/backend_test.go: add a test where Resolve(ReleaseOnly: true, ID: "i-foreign") returns a fake instance without Crabbox labels and assert that release is rejected before DeleteServer is called.
  • internal/providers/aws/backend_test.go: add a positive test proving canonical Crabbox-tagged AWS leases still release and clean up provider keys.
go test ./internal/providers/aws ./internal/cli
go test ./...

Remaining uncertainty:

No live AWS call was made during discovery; the finding is based on current source flow and local scoring. Verifier can confirm with a fake AWS client regression test without touching real cloud resources.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0Emergency: data loss, security bypass, crash loop, or unusable core runtime.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:securityThis issue is about security boundaries, credentials, authz, sandboxing, or sensitive data.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions