github goshs-labs/goshs v2.1.6

6 hours ago

What Changed in v2.1.6

This release turns the old shared clipboard into a full team chat for the web UI and the TUI, and resolves nine coordinated security advisories across the HTTP, WebDAV, SMB, TFTP and collaborator surfaces, plus the usual dependency and CI maintenance.

✨ New Features

  • Team chat (replaces the shared clipboard) — The non-persistent clipboard has grown into a live, collaboration-focused chat, synchronized over the websocket hub across every browser and the --tui dashboard (which authors as tui@<host>). Highlights:

    • Markdown rendering with the full :shortcode: emoji catalog (~1800 emoji), composer autosuggest, and collapsible long code blocks.
    • Emoji reactions (with a who-reacted tooltip) and in-place editing of your own messages (↑ in the composer recalls and cycles them; edits are flagged (edited)).
    • Image paste (inlined as base64, or written to disk with --persist-chat-images) and file upload via 📎 (POST /?chatUpload.goshs-chat/, respects --read-only, hidden from the listing).
    • Own-message highlight and opt-in desktop notifications (🔔 toggle) for others' messages when the tab is hidden.
    • Opt-in persistence--persist-chat writes the full log (messages, edit flags, per-emoji reaction authors) to <webroot>/.goshs-chat/chat.json and restores it on restart; in memory only by default.
    # Chat is on by default; persist it across restarts and store pasted images on disk
    ./goshs --persist-chat --persist-chat-images
    
    # Disable the chat entirely
    ./goshs --no-chat

    Flags: -nc/--no-chat (replaces the old --no-clipboard), -pc/--persist-chat, -pci/--persist-chat-images.

🔒 Security

Nine coordinated advisories, all remotely and (by default) unauthenticated.

Content-destruction / mode-flag bypasses under --no-delete / --upload-only / --read-only (#256) — Across every write protocol, --no-delete/--upload-only now treat overwrite, in-place write, truncate and rename/move of a pre-existing file as deletion-class operations and refuse them, while still allowing new-file creation and the operator's own create→write→rename upload flow.

  • SMB WRITE opcode overwrite (GHSA-275v-rxgc-4rcj, High) — the SMB2 WRITE opcode ignored the flags, allowing in-place overwrite of existing files.
  • SMB overwrite disposition & SET_INFO truncate (GHSA-jx6h-2x8x-hf5r, High)FILE_OVERWRITE/OVERWRITE_IF/SUPERSEDE creates and SET_INFO allocation/EOF truncation destroyed existing file contents.
  • SMB rename/clobber (GHSA-ppvh-3pc7-mvxw, High)FileRenameInformation moved and clobbered existing files.
  • TFTP --no-delete ignored (GHSA-2q29-798w-6qcp, High) — a TFTP WRQ ignored --no-delete, allowing overwrite and truncation of existing files.
  • TFTP WRQ destroys served files (GHSA-vw29-46p5-7h7x, High) — an unauthenticated WRQ could truncate any served file (os.Create implies O_TRUNC).
  • HTTP DELETE on block-listed files (GHSA-ppmc-5w4w-2669, High) — incomplete fix of CVE-2026-40189: .goshs block-listed files could still be removed via HTTP DELETE; the block list is now enforced before removal, mirroring the read/share/bulk/WebDAV paths.
  • WebDAV LOCK plants empty files (GHSA-whqg-vqcj-px54, Medium) — the library's LOCK handler plants lock-null empty files for absent paths, bypassing --read-only/--upload-only; webdavGuard now refuses LOCK/UNLOCK in those modes.

The four SMB sinks now route through SMBServer.protectExisting(), which blocks only when a flag is set and the path is not one the current session just created.

Credential & ACL exposure (#234)

  • Collaborator feed leaks the .goshs Authorization header (GHSA-wfg4-m42q-9pvq, High) — a legitimate write to a .goshs-protected directory carries Authorization: Basic …; the collaborator feed (anonymous when no global -b/-P is set) still broadcast that header on write paths, leaking per-directory ACL credentials to any watcher. The feed now strips Authorization (alongside the CSRF token) unconditionally, at every call site.
  • Block-only .goshs erases an ancestor's auth (GHSA-cfhc-8j7j-54wq, High)findEffectiveACL returned the nearest non-empty .goshs, so a block-only child ({"block":[…]}, no Auth) shadowed and erased a parent directory's auth requirement, yielding unauthenticated reads of the protected subtree. ACLs are now merged up to the webroot: the nearest ancestor that sets Auth wins (a nearer block-only file can never clear it), and block lists are unioned (fail-closed).

🛠️ Build, CI & Packaging

  • Migrated the integration test harness dependency (testcontainers-go 0.43 → 0.44).
  • Star History chart link updated in the README.

⬆️ Dependencies

  • Go modules: github.com/emersion/go-smtp 0.24.0 → 0.25.0, github.com/fclairamb/ftpserverlib 0.32.1 → 0.32.3, golang.org/x/text 0.40.0 → 0.41.0, github.com/moby/go-archive 0.2.0 → 0.3.0, github.com/testcontainers/testcontainers-go 0.43.0 → 0.44.0.
  • GitHub Actions: github/codeql-action (init/autobuild/analyze/upload-sarif) 4.37.3 → 4.37.7, docker/setup-buildx-action 4.2.0 → 4.3.0.

Don't miss a new goshs release

NewReleases is sending notifications on new releases.