Skip to content

[security] Workspace SSH host private keys are persisted in cloud provider user-data #1003

Description

@coygeek

[security] Workspace SSH host private keys are persisted in cloud provider user-data

Summary

Workspace provisioning generates an Ed25519 SSH host key pair so the coordinator can verify the SSH server it connects to for workspace terminal and native VNC access. The private half of that generated host identity is then copied into the lease config and rendered directly into Linux cloud-init ssh_keys user-data. AWS sends that blob as EC2 UserData, Azure sends it as VM customData, and GCP sends it as instance metadata user-data.

This crosses Crabbox's supported security boundary because the maintainer security policy treats "generated credentials being exposed beyond the current OS user by Crabbox" as in scope. Repository-selected commands and trusted project automation are expected behavior, but this is a Crabbox-generated credential for a coordinator-managed workspace identity. Persisting it in provider metadata exposes the credential to the provider account/control plane and any IAM principal or audit-log reader that can inspect launch user-data for the deployment.

Affected Components

  • worker/src/fleet.ts:3353-3359: Workspace provisioning generates a per-workspace Ed25519 SSH host key pair and immediately uses it to build the internal lease creation request.
  • worker/src/fleet.ts:13293-13309: workspaceLeaseRequest base64-encodes both the generated private and public host keys into internal request headers.
  • worker/src/fleet.ts:2041-2057: The lease creation path requires those workspace host-key headers and copies the decoded private key into LeaseConfig.sshHostPrivateKey.
  • worker/src/bootstrap.ts:55-73: Linux cloudInit includes the optional SSH host-key block in the top-level cloud-init document.
  • worker/src/bootstrap.ts:688-701: optionalSSHHostKeys renders config.sshHostPrivateKey verbatim under ssh_keys.ed25519_private.
  • worker/src/aws.ts:1155-1163: AWS instance creation sends the rendered bootstrap data as EC2 UserData.
  • worker/src/azure.ts:1142-1185: Azure VM creation base64-encodes the same Linux cloudInit(config) output and attaches it to the VM osProfile.
  • worker/src/azure.ts:1246-1257: Linux Azure VMs place that value in osProfile.customData.
  • worker/src/gcp.ts:293-303: GCP VM creation places the same cloudInit(config) output in instance metadata item user-data.
  • worker/src/fleet.ts:13671-13693: Workspace SSH connections verify the observed server host-key fingerprint against the stored expected fingerprint, so disclosure of the matching private key undermines an active host identity check.

Attack Path

An operator provisions a coordinator-managed workspace on a cloud provider-backed target such as AWS, Azure, or GCP. During provisioning, the coordinator generates a fresh Ed25519 SSH host key pair for that workspace and stores the public-key fingerprint for later SSH host verification. The private key is then carried through the internal workspace lease request into LeaseConfig.sshHostPrivateKey.

When the provider adapter builds the VM bootstrap payload, Linux cloud-init receives an ssh_keys section containing the full private key. The provider adapter then sends that bootstrap payload to the cloud provider as launch user-data, Azure custom data, or GCP instance metadata.

An attacker does not need Crabbox application access for this step. Any principal with sufficient read access in the cloud account, console, provider support path, or audit-log storage for instance creation/user-data can retrieve the generated SSH host private key after the workspace is launched. With that key and a suitable network position, the attacker can impersonate the workspace SSH server and satisfy Crabbox's expected host-key fingerprint check for subsequent workspace SSH, terminal, or native VNC connections.

Impact

The exposed value is a generated workspace credential, not trusted repository automation or an operator-supplied project secret. Disclosure gives cloud-account readers the private key for the SSH server identity that Crabbox expects for that workspace.

The practical impact is bounded by the workspace lifetime and by the attacker's need for provider-side read access plus a path to intercept or redirect later SSH traffic. Within those bounds, the leaked key can defeat Crabbox's host-key verification for the affected workspace, enabling SSH server impersonation and confidentiality/integrity compromise of later workspace SSH-backed interactions.

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:L/I:N/A:N CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N
Calculator CVSS v3.1 Calculator CVSS v4.0 Calculator

The score reflects a provider-authenticated attacker who can read deployment user-data or equivalent audit material. The direct vulnerable-system impact is confidentiality loss of a generated workspace host credential; the downstream SSH impersonation risk depends on additional network positioning, and the per-workspace key limits blast radius.

Recommended Remediation Approach

Avoid placing generated SSH host private keys in provider-controlled user-data or metadata. The safer design is to generate the host key inside the guest during first boot and return only the public host identity to the coordinator through a narrowly scoped, authenticated readiness channel. If coordinator-side generation remains necessary, deliver the private material over a channel that is not retained as provider launch metadata and document the trust properties clearly.

Add regression coverage that fails if SSH private key material appears in Linux cloud-init output, AWS EC2 user-data, Azure custom data, or GCP instance metadata. Existing workspace host-key tests should be updated to verify that only public host identity or fingerprints leave the guest/trusted channel.

Validation

Validation used source review and targeted test inspection against commit 52d272fbc45e49a6cf2a8027a996379eeadcd0c7.

  • worker/src/fleet.ts:3353-3359 generates the workspace host key pair, and worker/src/fleet.ts:13293-13309 places the private key in an internal lease request header.
  • worker/src/fleet.ts:2041-2057 decodes that header and stores the private key on the lease config used by provider provisioning.
  • worker/src/bootstrap.ts:55-73 and worker/src/bootstrap.ts:688-701 render the private key into the Linux cloud-init ssh_keys.ed25519_private field.
  • worker/src/aws.ts:1155-1163, worker/src/azure.ts:1142-1185, worker/src/azure.ts:1246-1257, and worker/src/gcp.ts:293-303 show that the same bootstrap payload is sent to AWS, Azure, and GCP provider launch metadata paths.
  • worker/src/fleet.ts:13671-13693 confirms Crabbox later verifies SSH host identity against the generated public-key fingerprint, so disclosure of the corresponding private key affects a real security check.
  • worker/test/bootstrap.test.ts:65-77 currently asserts that cloudInit() contains ed25519_private private-key material when sshHostPrivateKey is set, and worker/test/fleet.test.ts:5530-5617 asserts workspace lease creation supplies a generated OpenSSH private key to the provider config. No inspected regression test asserts that generated SSH host private keys are excluded from provider user-data or metadata.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal priority bug or improvement with limited blast radius.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