3.2 KiB
Security policy
Reporting a vulnerability
Please do not open a public issue for security problems.
Instead, report it privately to a maintainer — message an op on #orbit
(Libera.Chat or the Tchatou network). We'll acknowledge it, work on a fix,
and credit you (if you'd like) once it's resolved.
Supported versions
Orbit is a work in progress; only the latest main is supported. Fixes land
there and deploy from it.
Scope & trust model
A few things that are intentional, not bugs:
- Plugins run with full page privileges. Orbit's plugin system is
operator-controlled — a deployment lists plugin scripts in
config.json, so they run with the same trust as the app itself. There is no user-uploaded plugin mechanism. Only load plugins you trust; treat them like part of your deployment. See the plugin docs. - The client is static. It holds no server-side secrets; account auth is via
the IRC server (SASL) and the connection is TLS (
wss://).
Things we do want to hear about: ways a remote party (a malicious message, channel, or server response) could run code, steal a session, or break out of the intended sandbox in the client.
Hardening a deployment
Subresource Integrity for plugins
Pin any plugin served from a third-party origin with an SRI hash, so a
compromised host can't silently swap the file. A plugins entry may be an
object instead of a bare URL:
{
"plugins": [
"/app/plugins/orbit-clock.js",
{ "url": "https://cdn.example/orbit-x.js", "integrity": "sha384-…" }
]
}
Generate the hash with: openssl dgst -sha384 -binary file.js | openssl base64 -A
(prefix the result with sha384-). Same-origin plugins don't strictly need it.
Content-Security-Policy
Orbit ships no <meta> CSP because the right policy depends on your deployment
(IRC WebSocket host, whether you use the Turnstile challenge, where plugins are
hosted). Set it as a response header at your edge. A good starting point, with
the parts you must adjust marked:
# Replace wss://YOUR-IRC-HOST with config.json → server.url's origin.
# Add any off-origin plugin hosts to script-src. Drop the challenges.cloudflare.com
# lines if you don't use the Turnstile challenge. frame-src 'self' is required for
# sandboxed plugins; youtube-nocookie serves the inline YouTube link cards.
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' https://challenges.cloudflare.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data: blob: https:;
connect-src 'self' wss://YOUR-IRC-HOST;
frame-src 'self' https://challenges.cloudflare.com https://www.youtube-nocookie.com;
worker-src 'self';
manifest-src 'self';
base-uri 'self';
form-action 'self';
object-src 'none';
frame-ancestors 'self';
" always;
Roll it out with Content-Security-Policy-Report-Only first and watch the
browser console / report-to for violations, then switch to the enforcing
header once it's clean. Self-hosting the Google Fonts CSS/woff2 files lets you
drop the fonts.googleapis.com / fonts.gstatic.com origins entirely.