Skip to content

Security: pandorica-scientific/continuum

SECURITY.md

Security Policy

Continuum holds a household's bank statements, balances, payslips and documents. A vulnerability here is not an abstract one, so reports are welcome and taken seriously.

Reporting a vulnerability

Do not open a public issue for a security problem.

Report it privately, either way:

  • GitHub → the repository's Security tab → Report a vulnerability (private advisory, preferred — it keeps the discussion and the fix together).
  • Email robert.kiewisz@gmail.com with continuum security in the subject.

Please include:

  • what an attacker can do, and what they need to start (network access? a valid session? an upload?);
  • the affected version or commit, and how the instance is deployed (docker compose, reverse proxy, exposed to the internet or LAN-only);
  • steps to reproduce — a request, a crafted file, a code path;
  • anything you already know about a fix.

Redact real financial data from the report. A crafted statement with invented account numbers proves a parser bug just as well as a real one.

What to expect

This is a single-maintainer project, so the timelines are honest rather than corporate:

Stage Target
Acknowledgement that the report arrived 7 days
Assessment: confirmed, rejected, or scope 14 days
Fix released for a confirmed issue 30 days

You will be credited in the advisory and the changelog unless you prefer otherwise. Please give a coordinated-disclosure window of 90 days, or until a fix ships if that comes sooner.

Never test against an instance you do not own

Every Continuum instance is somebody's household. Test against your own deployment only — a fresh one with DEMO=1 costs a minute and contains nothing real. Probing someone else's server is not research.

Supported versions

Continuum is pre-1.0 and ships from main. Only the latest release receives fixes; there are no maintenance branches. Upgrading means pulling the current image — migrations run on start.

Version Supported
Latest release Yes
Anything older No

What the deployment assumes

These are design decisions, not vulnerabilities. Knowing them helps you judge whether a finding is in scope:

  • A trusted local network. Continuum speaks plain HTTP on port 80 and terminates no TLS of its own. It is built to sit on a home LAN behind a router, reachable as http://continuum.local, where the people who can reach it are the people who live there. A reverse proxy of your own can put HTTPS in front of it. Exposing it directly to the public internet is a deployment choice the app cannot defend against.
  • Form submissions are checked against the address the browser used. The Origin header must match the Host the request was sent to, so a page on another site cannot post to your ledger. /api is the one exception: it answers only a bearer token, which a cross-site form cannot attach, and does not even look the sign-in cookie up. Scheme is not compared: the app speaks HTTP and learns about TLS only from a proxy header, so comparing it would mean guessing. The residual gap is somebody who can already forge Host or terminate TLS inside your network, who is past this fence anyway.
  • Cookies follow the request. An auth cookie is marked Secure when the proxy in front says the browser used https, and not otherwise — so a plain LAN sign-in is never handed a cookie the browser will drop.
  • Everyone with an account can read the whole ledger. There is no multi-tenancy and no per-person data isolation: people are separate sign-ins over one shared household, by design. Roles separate administration only — members cannot manage people, tokens, modules, currency or backups, and those sections are never sent to them rather than merely hidden.
  • Backups are plain SQL. The scheduled backup writes an unencrypted continuum-backup.sql plus copies of every uploaded file. Pointing CONTINUUM_BACKUPS at a cloud-synced folder hands that content to the sync provider. Encrypt the destination if that matters to you.
  • Demo mode is public by construction. DEMO=1 seeds a fictional household with a published password. Never enable it on an instance holding real data.

Current protections, for reference when assessing a report: passwords hashed with Argon2id; session tokens, API tokens and enrollment links stored hashed, never in plaintext; enrollment links single-use, expiring and consumed in the same transaction that creates the password/session; authentication generations preventing an in-flight sign-in from surviving a password change/deactivation; failed sign-ins limited by both account and address, with separate bounded budgets for bearer tokens and enrollment; /api bearer enforcement and each token's access (read-only unless an administrator chose read-write) and areas (everything, or only the areas an administrator ticked) decided at the route boundary, failing closed for a route nobody placed, with the sign-in tables, settings, password hashes and calendar credentials unreachable through the API to either; files attached over the API are PDFs checked by their contents and stored under a name the server mints; and no webhooks. Initial setup is one atomic singleton claim and caps the submitted household at twenty people before any password hashing begins.

In scope

  • Authentication or session bypass; token forgery, reuse after revocation, or privilege escalation from member to administrator.
  • Enrollment-link flaws: a link that works twice, after expiry, after the person was deactivated, or that can be guessed from another one.
  • Anything letting an unauthenticated caller read or modify ledger data.
  • Injection: SQL, command, or template — including through parsed statement fields.
  • Stored or reflected XSS, particularly through imported statement text, document names, notes and tags.
  • Path traversal or arbitrary file read/write through document upload, file serving, or the backup path settings.
  • Server-side request forgery through the Home Assistant provider, the FX rate fetch, or any other outbound request whose target is user-controlled.
  • Secrets leaking into logs, error pages, the API, or backups.
  • A dependency vulnerability with a demonstrated path through Continuum's own code.

Out of scope

  • Anything requiring physical access to the server, or an already-authenticated session belonging to the attacker.
  • Consequences of exposing the instance to the internet without TLS or a proxy, or of running it on an untrusted network — see the assumptions above.
  • Denial of service by resource exhaustion from an authenticated household member (huge uploads, expensive queries).
  • Missing security headers, cookie-flag nitpicks, or scanner output with no demonstrated impact.
  • Self-XSS, clickjacking on pages with no state-changing action, and reports that amount to "the demo password is public".
  • Social engineering, phishing, or attacks on the maintainer's accounts.

If you are unsure which side of the line a finding falls on, report it privately anyway and say so.

There aren't any published security advisories