Security & Privacy
This page explains, in plain language first and technical detail after, how Oscilla handles safety and privacy — what it protects, what it deliberately does not try to do, and how to run it safely. It is written to be read by performers and organisers as much as by developers.
In one paragraph
Oscilla is a tool you run on your own computer, for yourself and for the musicians in the room with you. It keeps no accounts, no passwords, and no personal data — only the scores you make: drawings, audio, images and timing. It is built for a rehearsal room or a venue's local network, not to be published on the open internet. The parts that can change the computer's settings are locked to the machine actually running Oscilla; other people's phones and laptops on the same network can follow and annotate the score, but not reconfigure the software. The code is open source, so anyone can check these claims for themselves.
What Oscilla is, and what that means for safety
Oscilla is a local server. When you start it, your own computer becomes the host, and other devices on the same network — the players' tablets, a second laptop, a projector machine — open the score in a normal web browser by visiting the host's address. There is no Oscilla "cloud": nothing you make is sent to us or to anyone else unless you choose to share the files yourself.
Because everything runs on hardware you control, the security model is the same as any document you keep on your own machine. The important questions are therefore narrow and answerable:
- Who can change the score? Only the host machine can edit and reconfigure.
- Who can see the score? Anyone you let onto the network the host is on.
- What can a score itself do? A score is a document, but a rich one — see Scores are documents you should trust, below.
What we protect against
Reaching outside the score folder. Every file Oscilla reads or writes on
behalf of a browser is confined to your projects folder. A request cannot use a
crafted name (../../ and the like) to climb out and read your private files or
write elsewhere on disk. This is enforced in one central place that every
file operation passes through, and it is covered by automated tests so it cannot
quietly regress. This class of problem was found and closed in a September 2026
security review; the tests exist specifically so it stays closed.
Changing the machine's setup from another device. The powerful operations — changing server or network settings, restarting, updating, installing the desktop launcher, browsing the host's folders from the settings dialog — are host-only. A request for any of them from another device is refused. Editing the score is treated the same way: the host can edit, guests follow.
Untrusted file uploads. When a file is published into a project over the network, its type is checked against an allow-list (scores, audio, images, PDFs, text), its destination is confined to the project, and it is explicitly forbidden from landing in the folder where a project's code extensions live — so an upload cannot smuggle in a script that would later run.
What Oscilla does not try to do
Being honest about the boundaries is part of taking security seriously.
- It is not built to face the public internet. Oscilla has no logins, because it is meant for a trusted local network where everyone in the room is a collaborator. Do not port-forward it to the open internet or run it on an untrusted public network. If you genuinely need remote access, put it behind a VPN or an authenticating reverse proxy that you control (see Running it safely).
- It does not authenticate the people on your network. On the network it is serving, it assumes the devices that can reach it are ones you trust. That is the right assumption for a rehearsal room and the wrong one for a café's open Wi-Fi.
- It does not encrypt traffic by default. Plain HTTP is fine on a private network; HTTPS is available if you supply a certificate (see below).
Scores are documents you should trust
A score is more than a picture. It can carry timing logic and — through the
ext() feature — small pieces of JavaScript that run in the browser showing
the score, to drive custom visuals or behaviour. That power is what makes
Oscilla expressive, but it means a score behaves like a document that can
contain code, in the same way a spreadsheet can contain macros.
The practical guidance is simple: open scores from people you trust, just as you would only enable macros in a document from a known sender. A score you authored, or one shared by a collaborator, is exactly as safe as they are. The publish-upload path deliberately refuses to place files into the extensions folder over the network, so extensions can only be added by someone with direct access to the host's files — not by a passing network client.
Privacy
- No accounts, no tracking, no analytics. Oscilla does not phone home.
- No personal data is collected or required. The only things stored are your projects.
- Your work stays on your disk. Scores live in a projects folder on your own computer. Sharing happens only when you export a file and send it yourself.
- Client display names you type for a session (to tell players apart on screen) are used only within that session and are not persisted beyond it.
Running it safely
- Run Oscilla on a network you control — your own machine, a rehearsal-room router, a venue LAN you trust.
- Keep it off the public internet. If remote players must join, bridge them in with a VPN rather than exposing the port.
- For an encrypted connection on your network, start the server with a TLS
certificate and key (
--ssl-cert/--ssl-key, or theSSL_CERT_PATH/SSL_KEY_PATHenvironment variables) and Oscilla will serve over HTTPS. - Treat scores like documents: open the ones you trust.
- Keep Oscilla updated — fixes like the one above reach you through the normal update.
Technical detail
For readers who want the specifics behind the summary above.
Trust boundary
Oscilla binds an HTTP (or HTTPS) server and a WebSocket on the host. There is no authentication layer by design: the trust boundary is the network the host is attached to. Two privilege levels exist within that boundary:
- Host — requests originating from the loopback interface
(
127.0.0.1/::1). Detected byisLocalRequest(), surfaced to the UI ascanEdit, and enforced on sensitive routes by therequireLocalmiddleware. - Guest — any other device that can reach the server. Guests load and follow the score, contribute session annotations, and drive interactive elements; they cannot reconfigure the software.
requireLocal gates: server log, restart, launcher install/status, update
check/apply, server config, OSC config, host directory browse/mkdir, and project
migration.
Filesystem containment
All project-scoped filesystem access funnels through a single resolver
(resolveProjectDir / resolveProjectFile in serverUtils.js). That resolver:
- validates the project name against a strict allow-list pattern (letters, digits, spaces, hyphens, underscores — no dots, no path separators), and
- asserts, with a separator-aware prefix check (
assertInside), that the resolved path is contained within a projects root — and contains any request-supplied sub-path (audio/…,images/…,versions/…) the same way.
Placing the check at the resolver — rather than at each of ~50 routes — is
deliberate: a per-route check is opt-in and was historically forgotten on new
routes, which is how a traversal bug recurred. The two directory-listing
handlers that do not go through the resolver (/scores/*, /shared/*) strip
., .. and separators from their wildcard before joining. Regression tests
live in test/pathSafety.test.js and run under npm test.
Percent-encoded traversal (%2f) is covered: the encoding is decoded only after
routing, so the resolver sees real separators and rejects them.
Uploads
Network publish uploads (/api/project/:name/file) validate the project name,
normalise and reject ../absolute destination paths, restrict extensions to an
allow-list (.svg .json .wav .flac .mp3 .ogg .aiff .aif .png .jpg .jpeg .gif .webp .pdf .txt .md), forbid the extensions/ subtree, and re-assert
containment on the resolved destination. Audio/video ingest uploads are size-
capped and streamed to disk. JSON request bodies are capped at 10 MB.
Executable content
Projects may contain extensions/*.js, loaded and executed in the browser
client via the ext() cue. This is intended capability, not a flaw, but it
means a project is executable content and should be trusted like one. The
network upload path refuses the extensions/ directory, so extensions can be
introduced only by a party with direct filesystem access to the host.
Transport
HTTP by default; HTTPS when a certificate/key pair is supplied. Suitable for a
private network. isLocalRequest reads the socket's remote address directly —
correct for a direct bind, but note that placing a reverse proxy in front would
make every request appear local unless the proxy is configured as trusted and
the check moved to a validated forwarded header.
Reporting a problem
Security is treated as ongoing work, not a one-time checkbox: the codebase is open, the containment guarantees are tested, and known follow-ups are tracked in the repository. If you find a security issue, please report it privately to the maintainer (see the repository's contact details) rather than opening a public issue, so it can be fixed before it is widely known.
Tip: use ← → or ↑ ↓ to navigate the docs