soundbox
- Type
- MCP server
- Scanned
- Oct 30, 2026
- Version
- 085e0ecef754
- Files read
- 525
Soundbox is a local AI studio, desktop app, and MCP server that generates sound effects, music, and speech on your computer using open-weight models. The biggest risk is that its server has no authentication and disables browser security checks when listening on all network interfaces (such as in Docker), which could let attackers or malicious websites write files to arbitrary folders, steal saved API keys, or send unchecked options to the underlying audio engine.
What it can reach
- Files
- Reads and writes audio files, model weights, SQLite databases, logs, and settings under ~/.soundbox (or custom folders), installs skill files into coding agent folders (such as ~/.claude and ~/.cursor), and exposes an API to browse host directories.
- Network
- Runs a local HTTP API, web UI, and MCP server on port 17494, downloads AI models and runtime binaries from Hugging Face and GitHub, and connects to user-configured external AI and OpenTelemetry endpoints.
- Shell commands
- Spawns local AI inference binaries (audio.cpp, llama-server, sd-server), ffmpeg for audio conversion, nvidia-smi for GPU checks, archive tools (tar, unzip), and OS file managers.
- Secrets
- Reads Hugging Face tokens from environment variables (HF_TOKEN, HUGGING_FACE_HUB_TOKEN) and stores tokens and external AI API keys in settings.json.
- Browser
- Accesses microphone input and connected Web MIDI controllers through the web interface when triggered by the user.
- System
- Queries GPU and VRAM hardware information and interacts with local audio and MIDI devices.
Findings
-
MediumDocker container binds unauthenticated server to 0.0.0.0 by default
The Docker entrypoint defaults to binding the Soundbox HTTP and MCP server to 0.0.0.0 on port 17494, and the server has no authentication. If a user publishes the port without explicitly restricting it to 127.0.0.1 on the host, anyone on the network can call the API and MCP tools, consume GPU resources, and access or delete library audio.
Fix: Document and configure host port bindings to 127.0.0.1:17494:17494 by default, or require an authentication token when binding to non-loopback interfaces.
-
MediumWildcard host binding disables DNS-rebinding and CORS origin checks (including in Docker)
When the server is started with
--host 0.0.0.0(which is the defaultCMDin theDockerfile),cli.tspassesallowedHosts: "any"tobuildApp(). Inserver/src/app.ts,allowedHosts === "any"completely skips theHostheader check, even ifSOUNDBOX_ALLOWED_HOSTSis set. Meanwhile,isTrustedOrigin()inserver/src/origins.tsassumes theHostheader was already validated byapp.tsand trusts anyOriginheader whose host matches theHostheader (host === hostHeader.trim().toLowerCase()). As a result, even if a user publishes the Docker container port only to127.0.0.1:17494on their host, any malicious website can use DNS rebinding (sending matchingHostandOriginheaders for the attacker's domain) to bypass both the Host check and CORS preflight protection and make arbitrary unauthenticated requests to the Soundbox API.Fix: Do not disable the Host header check when bound to
0.0.0.0or::. Instead, always enforce theLOOPBACK_HOSTSandSOUNDBOX_ALLOWED_HOSTSallowlist inapp.tsunless the user explicitly opts out via a dedicated flag or wildcard entry inSOUNDBOX_ALLOWED_HOSTS. -
MediumUnfiltered model load and request options passed to audio.cpp
Both
speakRequestSchemaand the story segment schemas accept arbitrary key-value pairs inrequest_options(exposed to MCP tools asdelivery) andload_options, which are forwarded as--request-optionand--load-optionflags toaudio.cpp. Some model family parameters (such asvoice_samplesin VibeVoice) accept filesystem paths, so an untrusted caller or prompt-injected agent could supply unexpected runtime flags or reference local files outside the sound library.Fix: Validate
request_optionsandload_optionsagainst an allowlist of safe parameter names and types defined for each model family inmodels/params.ts, and reject any parameter that accepts raw filesystem paths. -
MediumMissing UNC and path validation on audiocpp_models_dir setting
While
updateSettingsvalidatessounds_dirwithassertSoundsDirUsable(blocking Windows UNC network paths viaisUncPathand preventing nested directory moves),audiocpp_models_diris applied directly without UNC or path validation and immediately probed on disk byadoptDownloadedModels(). On Windows, settingaudiocpp_models_dirto a UNC path can force the server to connect to a remote SMB share and leak NetNTLM credentials, or point model storage and deletion at unintended directories.Fix: Apply the same
isUncPathand path safety checks used inassertSoundsDirUsabletoaudiocpp_models_dirbefore updating settings or scanning the directory. -
MediumArbitrary directory creation and file write in skill installer
When
targetis set to"dir",resolveTargetandinstallaccept any filesystem path (exposed viaskillInstallRequestSchemato the HTTP API) without path or UNC restrictions. Callinginstallcreates the target directory recursively and removes/overwrites subdirectories matching bundled skill names at any location writable by the server process.Fix: Restrict skill installation via the HTTP API to the predefined agent targets (
claude,cursor,codex), or reject UNC paths and restrict custom target directories to safe user workspace locations. -
MediumSaved endpoint API keys can be exfiltrated by changing the URL in a test or update request
server/src/endpoints/service.ts:94
When testing (
POST /api/endpoints/test) or updating (PUT /api/endpoints/:id) a custom audio endpoint,EndpointService.build()reuses the previously savedapi_keywheneverapi_keyis omitted from the request, even if theurlfield is changed to a different host. Because the HTTP API has no authentication, any local process or attacker able to reach the API can pass an existing endpointidwith an attacker-controlledurland cause the server to send the storedAuthorization: Bearer <api_key>header to that URL.Fix: Only reuse the stored
api_keywhen the endpoint'surl(or at least its scheme, host, and port) is unchanged; require the key to be re-entered if the target host changes. -
MediumDocker image binds to 0.0.0.0 by default, disabling Host-header DNS rebinding protection
The Docker container starts the server with
--host 0.0.0.0so that port forwarding from the host can reach it. However, in Soundbox's HTTP server, a wildcard bind (0.0.0.0) disables theHostheader allowlist check on/api/*and/files/*routes. Even when the port is published only on127.0.0.1:17494on the host, a malicious website visited in the user's browser can use DNS rebinding to read the library, browse host/container directories viaGET /api/fs/dirs, or trigger same-origin API actions.Fix: Keep the loopback
Hostheader allowlist active even when the socket is bound to0.0.0.0, requiring non-loopbackHostheaders to be explicitly listed inSOUNDBOX_ALLOWED_HOSTS. -
MediumUnfiltered delivery options from MCP tools are passed directly to audio.cpp as request options
server/src/models/audiocpp.ts:1461
The MCP speech tools (
soundbox.speak,soundbox.create_story,soundbox.add_lines,soundbox.update_line) accept an arbitrarydeliverykey-value map (Record<string, string>) and forward it intoAudioCppModel.speak()asrequestOptionswithout filtering keys against safe delivery parameters. Inaudio.cpp, request options for several families include local file path parameters (such asvoice_samplesin VibeVoice orvoice_model_pathandretrieval_index_pathin RVC), allowing an untrusted prompt injection in the agent to pass arbitrary local file paths into the native runtime.Fix: Validate
requestOptionskeys against an allowlist of safe numeric, boolean, and choice parameters defined for the model family inparamsFor(s.family), and reject file-path options. -
MediumDocker container binds unauthenticated server to 0.0.0.0 and disables API Host checks
The Docker image starts the server with
--host 0.0.0.0and has no authentication. As noted in docs/INSTALL.md, binding to0.0.0.0also turns off theHostheader allowlist for the web UI and/api/*routes. If a user runs the container with-p 17494:17494instead of restricting the host mapping to127.0.0.1, anyone on the network (or a malicious webpage via DNS rebinding) can read or delete the audio library, trigger GPU jobs, or reconfigure external endpoints.Fix: Keep the Host header allowlist active even when listening on 0.0.0.0, or require an API token when bound to a non-loopback address.
-
LowUnpinned moving tag used for third-party runtime base image
The Dockerfile pulls ghcr.io/0xshug0/audio.cpp using the moving tag full-cpu by default. Because this image supplies the native audiocpp_cli binary executed by the server, an upstream compromise or breaking daily build could introduce untrusted code into newly built containers.
Fix: Pin AUDIOCPP_TAG to a specific immutable digest or dated release tag by default.
-
LowDocker image uses a daily-moving upstream base image tag by default
The Dockerfile defaults AUDIOCPP_TAG to 'full-cpu', which the comments note is a moving tag updated daily on ghcr.io/0xshug0/audio.cpp. Building the container without overriding this build argument pulls unpinned upstream binaries that could change unexpectedly or be compromised.
Fix: Pin AUDIOCPP_TAG to a specific dated release tag or an immutable SHA-256 image digest by default.
-
LowContainer listens on 0.0.0.0 without built-in authentication
The container starts the Soundbox server bound to 0.0.0.0 on port 17494 so Docker port publishing can reach it, and the server has no authentication. If a user runs the container with
-p 17494:17494instead of binding to127.0.0.1:17494:17494, any device on the local network can call the API and MCP tools.Fix: Ensure docker run and compose configurations bind the host port to 127.0.0.1, or add optional token authentication to the server.
-
LowUnpinned mutable base image tag in Dockerfile
The Dockerfile uses
ghcr.io/0xshug0/audio.cpp:full-cpuby default without pinning an immutable digest or dated release tag. As noted in the Dockerfile comments, these upstream tags move daily, meaning a rebuild could pull modified or compromised upstream binaries without notice.Fix: Pin
AUDIOCPP_TAGto a specific dated release tag and/or pin the base image by its SHA-256 digest. -
LowUnpinned moving base image tag in Dockerfile
The Dockerfile uses a mutable daily tag (
full-cpu) for the third-party base imageghcr.io/0xshug0/audio.cppby default. If the upstream tag is compromised or modified unexpectedly, container builds could pull untrusted binaries.Fix: Pin
AUDIOCPP_TAGto a specific immutable release tag and image SHA256 digest by default. -
LowPredictable log file path in shared temporary directory
The Tauri desktop shell writes startup logs to a fixed filename (
soundbox-desktop.log) in the system temporary directory (/tmpon Unix and macOS) without checking file ownership or disabling symlink following. On a multi-user machine, another local user could pre-create a symlink at/tmp/soundbox-desktop.logto append log lines to files owned by the user running Soundbox.Fix: Write the desktop launcher log inside the user's private Soundbox data directory (
~/.soundbox) or user-scoped application log directory instead of the shared system temp directory. -
LowUnpinned daily-moving base image tag in Dockerfile
The Dockerfile defaults to the floating
full-cputag ofghcr.io/0xshug0/audio.cpp, which the comments note moves daily. Building the image without overriding this argument pulls mutable upstream binaries without digest or version pinning.Fix: Pin
AUDIOCPP_TAGto a specific dated release tag and SHA256 image digest by default. -
LowDockerfile uses a mutable daily base image tag by default
The Dockerfile builds on
ghcr.io/0xshug0/audio.cpp:full-cpuby default. As the comments note, this tag moves daily and contains the prebuiltaudiocpp_clibinary that runs inside the container, meaning builds are not reproducible and automatically pull unpinned upstream binaries.Fix: Pin
AUDIOCPP_TAGto a specific dated release tag and immutable SHA-256 image digest by default.