[security] Default --tailscale bootstrap executes Tailscale's remote install script as root without pinning
Summary
Crabbox's managed-Linux --tailscale workflow installs Tailscale by default with:
curl -fsSL https://tailscale.com/install.sh | sh
That command is generated into cloud-init and runs as root on the leased machine before tailscale up consumes the one-off auth key. The same function already contains a SHA-256-verified static-archive install path, but that path only runs when CRABBOX_TAILSCALE_INSTALL_MODE=pinned is set. Current documentation describes the default as the Tailscale package install script and documents the pinned mode as an opt-in alternative, so the issue is not missing documentation; it is that the documented default bootstrap still executes remote installer bytes without a Crabbox-controlled digest or signature check.
This is in scope under Crabbox's maintainer-authored security policy because it is an integrity failure in an artifact Crabbox downloads and installs as part of a documented default workflow. It does not depend on hostile tenants sharing a broker or on a trusted repository selecting local automation.
Affected Components
- Verification target:
crabbox main snapshot recorded for github-issue-5002 at commit ab1c29f3fd40fad7898a6bf109edd0a17678c937.
- Component: managed-Linux cloud-init bootstrap for Tailscale-enabled leases.
- Policy boundary:
crabbox/SECURITY.md lists integrity failures in downloaded default-workflow artifacts as in scope.
- Operations guidance:
crabbox/docs/security.md says Tailscale does not change the SSH/key/expiry model; crabbox/docs/features/tailscale.md documents --tailscale, brokered one-off auth keys, and the default installer mode.
Relevant source evidence:
internal/cli/bootstrap.go:1081-1084 appends the Tailscale bootstrap whenever cfg.Tailscale.Enabled is true.
internal/cli/bootstrap.go:1602 places cloudInitTailscaleInstallBootstrap() into the generated cloud-init script before tailscale up.
internal/cli/bootstrap.go:1642-1645 returns the unpinned remote script installer unless CRABBOX_TAILSCALE_INSTALL_MODE is exactly pinned.
internal/cli/bootstrap.go:1646-1659 implements the opt-in pinned branch by downloading a versioned .tgz and checking it with sha256sum -c -.
internal/cli/bootstrap_test.go:412-451 asserts the default Tailscale cloud-init contains https://tailscale.com/install.sh.
internal/cli/bootstrap_test.go:453-479 asserts pinned mode uses the archive URL and sha256sum -c - and does not use tailscale.com/install.sh.
docs/features/tailscale.md:27-32 documents crabbox warmup --tailscale and crabbox run --tailscale.
docs/features/tailscale.md:195-199 documents that the default installer mode runs Tailscale's package install script and that CRABBOX_TAILSCALE_INSTALL_MODE=pinned enables SHA-256 verification.
Attack Path
Attacker role:
An external supply-chain or network-position attacker who can cause the leased machine to receive malicious content for https://tailscale.com/install.sh. Examples include compromise of the upstream install script or its hosting/CDN path, or an enterprise/TLS-intercepting network position in the lease's egress path.
Prerequisites:
- The operator creates a managed Linux lease with Tailscale enabled, such as
crabbox warmup --tailscale or crabbox run --tailscale -- ....
CRABBOX_TAILSCALE_INSTALL_MODE is unset or set to the documented default package/script mode.
- The attacker controls the script body returned to the lease for
https://tailscale.com/install.sh.
Steps:
- The operator requests a managed Linux lease with
--tailscale.
cloudInitOptionalBootstrap includes the Tailscale bootstrap because cfg.Tailscale.Enabled is true.
cloudInitTailscaleBootstrap emits cloudInitTailscaleInstallBootstrap() before the later tailscale up command.
- In the default mode,
cloudInitTailscaleInstallBootstrap emits retry sh -c 'curl -fsSL https://tailscale.com/install.sh | sh'.
- Cloud-init executes the attacker-controlled script as root on the lease.
- The malicious script can persist on the lease, tamper with the Tailscale installation, and as root can inspect cloud-init/user-data material that includes the later one-off auth-key bootstrap.
Control flow:
documented --tailscale lease
-> cfg.Tailscale.Enabled
-> cloudInitTailscaleBootstrap
-> default cloudInitTailscaleInstallBootstrap
-> curl https://tailscale.com/install.sh | sh
-> root execution inside the managed Linux lease
Impact
Successful exploitation gives the attacker arbitrary root code execution inside managed Linux leases booted with the default --tailscale installer mode. The malicious code runs before Tailscale enrollment completes, so it can tamper with the installed client/daemon and can read bootstrap material available to root on the machine, including the one-off Tailscale auth-key content embedded later in the cloud-init flow.
The realistic blast radius is the affected lease and its bootstrap-time Tailscale identity, not the coordinator as a hostile multi-tenant platform. That still crosses a Crabbox-supported boundary because Crabbox itself is downloading and executing an external installer as part of a documented default workflow without binding the bytes to a reviewed digest or signature.
Severity Assessment
CVSS Assessment
| Metric |
v3.1 |
v4.0 |
| Score |
8.3 / 10.0 |
7.7 / 10.0 |
| Severity |
High |
High |
| Vector |
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H |
CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:L/SI:L/SA:N |
| Calculator |
CVSS v3.1 Calculator |
CVSS v4.0 Calculator |
The attack is network-adjacent to the external installer delivery path and requires the operator to create a Tailscale-enabled lease, so attack complexity is high and user interaction is required. If the installer bytes are compromised at bootstrap time, impact to the lease is high for confidentiality, integrity, and availability. Secondary impact to the Tailscale enrollment material is represented as limited subsequent-system impact in CVSS v4.0 rather than as full compromise of the entire tailnet.
Recommended Remediation
Make the SHA-256-verified static archive install path the default for managed-Linux --tailscale bootstrap, and reserve the current package-script installer for an explicit compatibility opt-out.
Concrete implementation direction:
- In
cloudInitTailscaleInstallBootstrap, run the existing pinned branch by default.
- Keep
defaultTailscaleVersion, defaultTailscaleAMD64SHA256, and defaultTailscaleARM64SHA256 as the reviewed defaults.
- Keep
CRABBOX_TAILSCALE_VERSION, CRABBOX_TAILSCALE_SHA256_AMD64, and CRABBOX_TAILSCALE_SHA256_ARM64 for reviewed updates and custom deployments.
- Rename or document the unpinned path as an explicit opt-out, for example
CRABBOX_TAILSCALE_INSTALL_MODE=package, and make that mode visibly less safe.
- Update
docs/features/tailscale.md and deployment docs so they describe the pinned default and the explicit package-script fallback.
- Add or update tests so default generated cloud-init contains the versioned archive URL and
sha256sum -c -, and so the package-script string appears only when the explicit fallback mode is selected.
Validation
Validation method:
Source review of the isolated verification workspace, with maintainer-authored policy and operations documents checked by SHA-256 against the verifier prompt.
Evidence:
crabbox/SECURITY.md SHA-256 matched 43cfd2f02d69e7febedd509695f498ae77fd9be1e2d84c8c2e9e8f504d63a85a.
crabbox/docs/security.md SHA-256 matched f51c7a3113abea1cc822c6161893d1fa9b451c65e77cb4ea358250066a20a962.
internal/cli/bootstrap.go:1643-1644 shows the default branch returns curl -fsSL https://tailscale.com/install.sh | sh.
internal/cli/bootstrap.go:1646-1659 shows the in-tree pinned mode downloads a versioned Tailscale archive and verifies it with sha256sum -c -.
internal/cli/bootstrap_test.go:412-451 confirms the current default generated cloud-init is expected by tests to include https://tailscale.com/install.sh.
docs/features/tailscale.md:195-199 confirms current documentation calls the package installer the default and pinned mode opt-in.
- CVSS values were checked with the local
cvss Python package: v3.1 score 8.3 High and v4.0 score 7.7 High for the vectors above.
Counterevidence considered:
- Pinned mode exists and is documented in the current checkout. That reduces the issue to the default path, but it does not remove the default-workflow integrity gap.
- The attack requires compromise or tampering of an external installer delivery path at lease boot time, so the finding is High rather than Critical.
- No live lease was launched during verification. The source and existing unit tests are sufficient to prove the generated default bootstrap string and the opt-in pinned alternative.
Suggested regression check:
go test ./internal/cli/ -run 'TestCloudInitTailscale'
[security] Default
--tailscalebootstrap executes Tailscale's remote install script as root without pinningSummary
Crabbox's managed-Linux
--tailscaleworkflow installs Tailscale by default with:curl -fsSL https://tailscale.com/install.sh | shThat command is generated into cloud-init and runs as root on the leased machine before
tailscale upconsumes the one-off auth key. The same function already contains a SHA-256-verified static-archive install path, but that path only runs whenCRABBOX_TAILSCALE_INSTALL_MODE=pinnedis set. Current documentation describes the default as the Tailscale package install script and documents the pinned mode as an opt-in alternative, so the issue is not missing documentation; it is that the documented default bootstrap still executes remote installer bytes without a Crabbox-controlled digest or signature check.This is in scope under Crabbox's maintainer-authored security policy because it is an integrity failure in an artifact Crabbox downloads and installs as part of a documented default workflow. It does not depend on hostile tenants sharing a broker or on a trusted repository selecting local automation.
Affected Components
crabboxmain snapshot recorded forgithub-issue-5002at commitab1c29f3fd40fad7898a6bf109edd0a17678c937.crabbox/SECURITY.mdlists integrity failures in downloaded default-workflow artifacts as in scope.crabbox/docs/security.mdsays Tailscale does not change the SSH/key/expiry model;crabbox/docs/features/tailscale.mddocuments--tailscale, brokered one-off auth keys, and the default installer mode.Relevant source evidence:
internal/cli/bootstrap.go:1081-1084appends the Tailscale bootstrap whenevercfg.Tailscale.Enabledis true.internal/cli/bootstrap.go:1602placescloudInitTailscaleInstallBootstrap()into the generated cloud-init script beforetailscale up.internal/cli/bootstrap.go:1642-1645returns the unpinned remote script installer unlessCRABBOX_TAILSCALE_INSTALL_MODEis exactlypinned.internal/cli/bootstrap.go:1646-1659implements the opt-in pinned branch by downloading a versioned.tgzand checking it withsha256sum -c -.internal/cli/bootstrap_test.go:412-451asserts the default Tailscale cloud-init containshttps://tailscale.com/install.sh.internal/cli/bootstrap_test.go:453-479asserts pinned mode uses the archive URL andsha256sum -c -and does not usetailscale.com/install.sh.docs/features/tailscale.md:27-32documentscrabbox warmup --tailscaleandcrabbox run --tailscale.docs/features/tailscale.md:195-199documents that the default installer mode runs Tailscale's package install script and thatCRABBOX_TAILSCALE_INSTALL_MODE=pinnedenables SHA-256 verification.Attack Path
Attacker role:
An external supply-chain or network-position attacker who can cause the leased machine to receive malicious content for
https://tailscale.com/install.sh. Examples include compromise of the upstream install script or its hosting/CDN path, or an enterprise/TLS-intercepting network position in the lease's egress path.Prerequisites:
crabbox warmup --tailscaleorcrabbox run --tailscale -- ....CRABBOX_TAILSCALE_INSTALL_MODEis unset or set to the documented default package/script mode.https://tailscale.com/install.sh.Steps:
--tailscale.cloudInitOptionalBootstrapincludes the Tailscale bootstrap becausecfg.Tailscale.Enabledis true.cloudInitTailscaleBootstrapemitscloudInitTailscaleInstallBootstrap()before the latertailscale upcommand.cloudInitTailscaleInstallBootstrapemitsretry sh -c 'curl -fsSL https://tailscale.com/install.sh | sh'.Control flow:
Impact
Successful exploitation gives the attacker arbitrary root code execution inside managed Linux leases booted with the default
--tailscaleinstaller mode. The malicious code runs before Tailscale enrollment completes, so it can tamper with the installed client/daemon and can read bootstrap material available to root on the machine, including the one-off Tailscale auth-key content embedded later in the cloud-init flow.The realistic blast radius is the affected lease and its bootstrap-time Tailscale identity, not the coordinator as a hostile multi-tenant platform. That still crosses a Crabbox-supported boundary because Crabbox itself is downloading and executing an external installer as part of a documented default workflow without binding the bytes to a reviewed digest or signature.
Severity Assessment
CVSS Assessment
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:HCVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:L/SI:L/SA:NThe attack is network-adjacent to the external installer delivery path and requires the operator to create a Tailscale-enabled lease, so attack complexity is high and user interaction is required. If the installer bytes are compromised at bootstrap time, impact to the lease is high for confidentiality, integrity, and availability. Secondary impact to the Tailscale enrollment material is represented as limited subsequent-system impact in CVSS v4.0 rather than as full compromise of the entire tailnet.
Recommended Remediation
Make the SHA-256-verified static archive install path the default for managed-Linux
--tailscalebootstrap, and reserve the current package-script installer for an explicit compatibility opt-out.Concrete implementation direction:
cloudInitTailscaleInstallBootstrap, run the existing pinned branch by default.defaultTailscaleVersion,defaultTailscaleAMD64SHA256, anddefaultTailscaleARM64SHA256as the reviewed defaults.CRABBOX_TAILSCALE_VERSION,CRABBOX_TAILSCALE_SHA256_AMD64, andCRABBOX_TAILSCALE_SHA256_ARM64for reviewed updates and custom deployments.CRABBOX_TAILSCALE_INSTALL_MODE=package, and make that mode visibly less safe.docs/features/tailscale.mdand deployment docs so they describe the pinned default and the explicit package-script fallback.sha256sum -c -, and so the package-script string appears only when the explicit fallback mode is selected.Validation
Validation method:
Source review of the isolated verification workspace, with maintainer-authored policy and operations documents checked by SHA-256 against the verifier prompt.
Evidence:
crabbox/SECURITY.mdSHA-256 matched43cfd2f02d69e7febedd509695f498ae77fd9be1e2d84c8c2e9e8f504d63a85a.crabbox/docs/security.mdSHA-256 matchedf51c7a3113abea1cc822c6161893d1fa9b451c65e77cb4ea358250066a20a962.internal/cli/bootstrap.go:1643-1644shows the default branch returnscurl -fsSL https://tailscale.com/install.sh | sh.internal/cli/bootstrap.go:1646-1659shows the in-tree pinned mode downloads a versioned Tailscale archive and verifies it withsha256sum -c -.internal/cli/bootstrap_test.go:412-451confirms the current default generated cloud-init is expected by tests to includehttps://tailscale.com/install.sh.docs/features/tailscale.md:195-199confirms current documentation calls the package installer the default and pinned mode opt-in.cvssPython package: v3.1 score8.3High and v4.0 score7.7High for the vectors above.Counterevidence considered:
Suggested regression check: