Fleet Deck 0.9.1
Security + hardening for the 0.9.0 image-paste feature, from an adversarial review.
Fixed a /tmp symlink-follow. 0.9.0 wrote pastes to a fixed, world-known name in shared /tmp, and the pruner followed a directory symlink planted there — on a multi-user host, a local co-tenant could turn a victim's paste into an arbitrary-file delete/overwrite as the victim. Single-user laptops and single-owner Coder workspaces were never exposed. Pastes now live under FLEETDECK_HOME, which no other user can write, so the symlink can't be planted at all.
Also: a burst of pastes can no longer clobber one another (128-bit names + exclusive write); the paste directory is bounded (keeps the 50 most-recent); oversized bodies are rejected before buffering; and — the most visible change — the feature is no longer silent. A too-large screenshot, an offline daemon, or an unsupported file now shows a status over the pane ("image too large (max 10 MB)", "✓ image added — press Enter to send") instead of doing nothing.
Recommended for anyone on 0.9.0, and required on shared/multi-user hosts.
Fixed
- Image pastes are written under
FLEETDECK_HOME, not a fixed name in shared/tmp. The 0.9.0 paste dir wasos.tmpdir()/fleetdeck-pastes— a world-known path in sticky/tmp— and the pruner followed a directory symlink planted there. On a multi-user host a local co-tenant could pre-create that symlink and turn a victim's paste into an arbitrary-file delete/overwrite as the victim's user (and, as a lesser variant, squat the name to break the feature for everyone else on the box). A single-user laptop or a single-owner Coder workspace was never exposed — this bites shared login/build hosts. The directory now lives underFLEETDECK_HOME, which no other user can write, so the symlink cannot be planted at all; the pruner additionallylstats every entry and never follows a symlink, and the dir is refused if it is not a real directory this user owns. - A burst of pastes can no longer clobber an earlier one. Filenames were a per-second timestamp plus 24 random bits; names are now a 128-bit
randomUUID, and the staging write is exclusive (wx). - The paste directory is bounded. Age-pruning (>24 h) only ran on the next paste and had no ceiling; it now also keeps at most the 50 most-recent files.
- The feature is no longer silent. Every failure path (too-large image, unreachable daemon, unsupported bytes, a pane that lost focus mid-upload) now shows a transient status over the pane instead of only a console warning. Success shows "image added — press Enter to send".
- Reject an oversized paste by its
Content-Lengthbefore buffering it; tighten the transport cap to what a 10 MB image actually needs; validate base64 up front instead of letting malformed input decode to garbage.