1e59d21dee5121a73619e0eadf6b8e24a68ffccc
updateTrack/updateArtist/updateAlbum built their SET clause from
Object.keys(data) where data is `request.body as any`, interpolating
request-supplied keys straight into SQL as quoted identifiers:
fields.map((f, i) => `"${f}" = $${i + 2}`)
A crafted body key closes the quoted identifier and injects into the SET
list. Mitigated in practice only by the LAN/VPN-only proxy — which supplies
the auth token automatically, so any device on the LAN could reach it from
a browser.
Adds per-table UPDATABLE_COLUMNS plus an allowedFields() helper, applied in
all three methods. The allowlist lives in the service layer rather than the
routes so it covers every caller.
Unknown keys are dropped rather than rejected: the three routes do no error
mapping, so a throw surfaces as a bare 500, and the pre-existing "No fields
to update" error still fires for a payload rejected in its entirety.
Also closes plain mass-assignment. Excluded: path/hash/mtime
(scanner-owned; path is the only link to the read-only bind),
state/quarantined_at/deleted_at (dislike lifecycle and integrity sweep),
play_count/skip_count/dislike_count/last_played_at (learning signal —
forgeable counters poison the engine), and identity/generated columns.
The only callers are the three HTTP PUTs; the frontend's update* service
exports are dead code, so nothing relied on writing an excluded column.
REVIEW-2026-07-30.md finding 5.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
muzick
A high-performance, distributed music orchestration and recommendation platform.
Overview
muzick is designed to manage a local music library while providing an "infinite vibe" listening experience. It bridges the gap between a local filesystem and advanced discovery engines through a tiered recommendation architecture.
Tech Stack
Frontend
- Framework: React
- Routing: TanStack Router
- Data Fetching: TanStack Query (with Look-ahead Buffering)
- State Management: Zustand (for Session/Vibe state)
- Styling: CSS Variables (Customizable Themes)
Backend
- Runtime: Node.js / TypeScript
- Framework: Fastify
- Task Queue: BullMQ (via Redis)
- Search: Typesense
Infrastructure & Data
- Database: PostgreSQL (Source of truth for metadata, relationships, and session state)
- Cache/Queue: Redis
- Audio Analysis: Essentia (via Worker processes)
- External Metadata: MusicBrainz, Discogs, LRCLib, Cover Art Archive
Core Concepts
- The Rolling Vibe: A continuous, evolving stream of music that uses a "Rolling Window" of tracks. It interleaves owned library tracks with high-probability "probation" tracks (external discoveries).
- The Dislike Lifecycle: A multi-stage state machine that protects users from accidental deletions while ensuring the library stays clean.
- Tiered Similarity: Instant metadata-based matches, followed by deep audio-feature similarity.
Getting Started
Prerequisites
- Docker & Docker Compose
Running Locally
docker-compose up -d
Description
Languages
TypeScript
95.5%
PLpgSQL
2.4%
CSS
1.4%
JavaScript
0.4%
Dockerfile
0.2%