Tobias GesellchenandClaude Opus 4.7 eab1b7a15a fix(security): close go/path-injection alerts via os.Root containment
The previous filepath.IsLocal-up-front pattern in safeJoin/safeJoin-equivalents
turned out not to satisfy CodeQL's go/path-injection rule — the post-validation
filepath.Join still constructs the joined string from tainted input, so the
analyser conservatively assumes the os.* sink that consumes it is tainted
too. Only one of 34 alerts closed on the previous attempt.

Switch to *os.Root (Go 1.24+, available on the project's 1.26.3 toolchain).
The Go runtime guarantees that operations on a Root cannot escape the
anchored directory regardless of what's in the relative path, and CodeQL has
a built-in model that recognises *os.Root.* methods as path-traversal
sanitisers. Result: every os.* sink in the datastore, marge, recorder,
mirror parity-mismatch writer, and docs handler is now reached only via a
*os.Root, which closes the rule-level alerts cleanly.

Changes per file:

* pkg/service/datastore/datastore.go — Adds a `root *os.Root` to DataStore,
  lazily opened at first use (after MkdirAll-ing baseDir) and closed by a
  new `(*DataStore).Close()`. Adds package-private helpers
  (rootStat / rootReadFile / rootWriteFile / rootMkdirAll / rootRemove /
  rootRemoveAll / rootRename / rootReadDir / rootOpen / rootExists) plus
  three exported wrappers (ReadDirUnderBase, MkdirAllUnderBase,
  WriteFileUnderBase) for the cross-package marge / handlers callers.
  Every os.* call that previously consumed safeJoin output now goes through
  these helpers. The post-join belt-and-suspenders prefix check inside
  safeJoin is preserved as a defence-in-depth fallback.

* pkg/service/marge/marge.go — Replaces the five `os.ReadDir(devicesDir)`
  call sites with `ds.ReadDirUnderBase(...)` so the datastore's root
  enforces containment.

* pkg/service/proxy/recorder.go — Mirrors the datastore pattern with its
  own `root *os.Root` anchored at Recorder.BaseDir, lazily opened. New
  helpers convert the eight existing `os.*` sites that consume sessionID
  / relPath / sanitizedSegments inputs. The earlier safeJoin (filepath.IsLocal
  pre-check) stays in place as the same belt-and-suspenders guard.

* pkg/service/handlers/handlers_docs.go — Opens a *os.Root at "docs" via
  sync.Once and reads file content (and SUMMARY.md sidebar) through it.
  Removes the prior filepath.IsLocal pre-check; the runtime now guarantees
  containment.

* pkg/service/handlers/mirror_middleware.go — Routes the parity-mismatch
  JSON write through `s.ds.WriteFileUnderBase` so the datastore's root
  performs the path-traversal sanitiser.

Behavioural fix: *os.File.ReadDir(-1) returns directory entries in
filesystem order, but os.ReadDir is documented to sort by name and at least
one regression test
(handlers.TestMargeAccountFullExcludesEmptyAmazonSource) depends on the
sorted contract. Both rootReadDir helpers explicitly sort by name to match.

All test suites pass for the touched packages; the unrelated
TestDocsConsistency failure about untracked working-tree docs is
pre-existing. golangci-lint reports 0 issues.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 15:18:24 +02:00
2026-03-06 21:26:24 +01:00
2026-05-08 21:21:52 +02:00
2026-05-10 12:58:00 +02:00
2026-04-28 17:57:46 +02:00
2026-05-08 21:21:52 +02:00
2026-01-08 22:59:34 +01:00

Bose SoundTouch Toolkit

Go Reference Go Report Card License: MIT

Independent project. Not affiliated with or endorsed by Bose Corporation.

Context: Cloud Shutdown

Bose is shutting down SoundTouch cloud services on May 6, 2026. After that, music service browsing, preset sync, and the official SoundTouch app stop working. This toolkit lets you keep your speakers fully functional.

See the Survival Guide for the full picture.


Tools

soundtouch-service — AfterTouch

A local server that replaces the Bose cloud ("AfterTouch"). Once your speaker is redirected to it, you have full control without any Bose cloud dependency. The built-in web UI at http://localhost:8000 handles all setup — no config files needed to get started.

If you want to run a server for this - no problem. The service is small enough to run on the SoundTouch itself. See the On-Device Installer for instructions.

Two scenarios:

Before shutdown — migrate your existing setup While the Bose cloud is still running, use soundtouch-backup to save your account data. The local service web UI then helps with the migration so your speaker keeps its presets and credentials.

After shutdown or factory reset — start fresh Create a local account, configure your speakers, and start using them immediately. No Bose infrastructure required.

Redirecting your speaker

The service needs a stable address on your local network (e.g. soundtouch.fritz.box or soundtouch.local). The speaker must then be redirected to resolve the Bose cloud hostnames to that address. Two supported methods:

Method How it works Notes
XML redirect Upload a config XML via the Web API Surgical; covers only registered endpoints; best for testing
DNS/DHCP Serve custom DNS on your network Covers all devices at once; requires port 53 and TLS

The web UI walks you through each method. DNS redirect requires HTTPS — the service manages its own CA certificate and the web UI guides you through trusting it on each speaker.

Note: A hosts-file method (direct SSH edits to /etc/hosts) also exists in the codebase but is deprecated and not exposed in the web UI.

Enabling SSH via USB stick

Some setup steps require SSH access to the speaker. Enable it once per device: create a file named remote_services on a FAT-formatted USB drive (the drive may need its bootable flag set — see SoundCork issue #172), and insert it while the speaker is powered on. After reboot, root SSH is available with no password.

See Device Initial Setup and Migration Guide for step-by-step instructions.


soundtouch-backup

Backs up your Bose cloud account (presets, paired devices, music sources) and each speaker's local state before the shutdown. Run soundtouch-backup all to capture everything in one step; it authenticates with the Bose cloud, then polls each paired speaker over the local network.

See the soundtouch-backup README for usage.


soundtouch-cli

Command-line control of any SoundTouch device: play/pause/volume, presets, source selection, multiroom zones, device discovery, and more. Works entirely over the local network — no cloud dependency. Well-suited for scripting and home automation.

See the CLI Reference for full usage.


soundtouch-web

A standalone web UI for device control — play, pause, volume, preset selection, real-time status — served from a local Go binary. Complements soundtouch-service when you want a dedicated device-control interface separate from the setup/admin UI.

See the soundtouch-web README for usage.


Go library

pkg/client provides a Go API for all SoundTouch device endpoints: media control, volume, presets, sources, zones, real-time WebSocket events, and device discovery. Use it to build your own integrations.

go get github.com/gesellix/bose-soundtouch

See the API Reference and pkg.go.dev for documentation.


Documentation


  • SoundCork (Deborah Kaplan et al.) — Python service interception; pioneered the cloud emulation approach this project builds on
  • SoundCork Stockholm App — Companion app for SoundCork
  • SoundTouch Plus (Todd Lucas) — Home Assistant integration; extensive undocumented API documentation
  • ÜberBöse API (Julius) — API research and advanced endpoint discovery
  • Bose SoundTouch Hook (Adrian Böckenkamp) — LD_PRELOAD hooking for reverse engineering device internals

Support


Star this project if you find it useful!


License

MIT — see LICENSE.

SoundTouch is a trademark of Bose Corporation.

S
Description
No description provided
Readme MIT
37 MiB
Languages
Go 88.8%
JavaScript 5.8%
Shell 2%
HTML 1.9%
CSS 0.8%
Other 0.7%