Please do not open a public issue for a security problem.
Report it privately through GitHub Security Advisories:
That opens a private thread visible only to you and the maintainer, and it is the only channel monitored for this. If GitHub advisories are unavailable to you, open a public issue containing no detail — just "security report, please make contact" — and a private channel will be arranged from there.
- What the issue is, and what an attacker gains from it.
- Steps to reproduce, or a proof of concept.
- Affected version or commit.
- macOS version, and whether
.venv-mlis installed.
This is a solo-maintained hobby project, so honesty about response times is more useful than a promise nobody can keep:
- Acknowledgement: within about a week.
- Assessment and a fix, or an explanation of why it isn't one: as soon as is practical after that.
- Credit: in the advisory and the release notes, unless you'd rather not be named.
There is no bug bounty. Nothing is paid for reports.
Please give a reasonable window before publishing — 90 days is the usual convention, and less is fine by agreement if a fix lands sooner. If a report goes unanswered for 90 days, publish; a silent maintainer is not a reason to sit on a real problem.
Only the latest commit on main is supported. There are no release branches
and no backports. Fixes land on main; users update by pulling and running
./djcrate restart.
DJ Crate is a single-user desktop application. Understanding that shapes what counts as a vulnerability.
The local HTTP server listens on 127.0.0.1:8765 — the loopback interface,
never 0.0.0.0. It is not reachable from your LAN, and not from the internet.
The API has no authentication, and that is a deliberate consequence of the bind
address rather than an oversight: the trust boundary is the machine, and
anything already running as your user on your machine can read ~/.dj_crate/
directly without going through the API at all.
A change that widens the bind address is a security change, not a convenience feature, and would need authentication designed alongside it. If you put the app behind a tunnel, a reverse proxy, or any form of remote access, you have moved it outside its threat model and taken on responsibility for authenticating it. (Note also that AGPL § 13 starts applying the moment other people interact with it over a network — see THIRD-PARTY-NOTICES.md.)
~/.dj_crate/config.json holds the mirror server's credentials, your Spotify app
credentials, and your Anthropic API key. It is written mode 0600 (owner
read/write only) and the values are plaintext — not encrypted, not in the
macOS Keychain.
This is a known, accepted limitation and it is stated here so nobody has to discover it. The reasoning: any process running as your user can read the Keychain for an app that can itself read the Keychain, so for a local single-user app the Keychain buys less than it appears to. It does buy something — at-rest protection if the file is copied off the machine, e.g. into a backup or a synced folder — so a Keychain-backed store is a welcome contribution, and the issue tracker is the place to propose it.
Practical advice in the meantime: don't put your crate folder or ~/.dj_crate
inside a cloud-synced directory, and use a scoped Anthropic key you can rotate.
- No audio, ever. Analysis is entirely on-device. There is no upload path in the codebase.
- Popularity and artwork lookups (Spotify / Deezer) send an ISRC, or an artist and title string. Off unless you configure them.
- The AI planner (Anthropic API) sends track metadata only — tempo, key, energy, cue times, section labels, vocal windows. Never audio, never file paths. Off until you supply a key and it validates.
- The HTTP mirror sends your Basic-Auth credentials to the server you
configured, over whatever transport that URL specifies. Use
https://.
- Anything reachable from a web page in another tab — the local server is loopback, but a browser on the same machine can still reach it. Cross-origin request forgery against state-changing endpoints, DNS rebinding, and missing origin checks are all in scope and are the most likely real finding here.
- Path traversal in the static file handler, the artwork cache, or any endpoint that takes a path.
- Command injection into the
ffmpegsubprocess calls, or into the.venv-mlworker invocation. - SQL injection in
library.py. - Anything that causes the app to write to or delete a file it does not own —
the
originguards around art embedding and duplicate-trashing are safety properties, and a way around them is a vulnerability, not a bug. - Credential leakage into logs, error messages, the rekordbox XML export, or API responses.
- Anything that lets a crafted audio file achieve code execution during analysis.
- The API having no authentication on loopback. See above — that's the design, and the trust boundary is the machine.
- Credentials being plaintext in a 0600 file. Documented above; proposals welcome as a feature, not as an advisory.
- Anything requiring an attacker to already have code execution as your user, or physical access to an unlocked machine.
- Vulnerabilities in ffmpeg, essentia, torch or any other dependency — report those upstream. If a dependency's flaw is reachable in a way that is specific to how DJ Crate calls it, that part is in scope, and is worth reporting here as well as upstream.
- The mirror server you point the downloader at. That's your infrastructure.
- Denial of service against your own local app.
Two habits matter more than any checklist:
- Never log a credential or an API key, including inside an exception message or a request dump.
- The
origincolumn is a safety boundary.art_embed_targetscarriesAND origin IS NULL, and/api/duplicates/trashrefuses a borrowed id unconditionally. Those two guards are what stand between the app and deleting files a user only lent it.docs/DESIGN.mdexplains why each is structural rather than a filter — read that section before touching either.