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.
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 securityin 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.
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.
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.
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 |
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
Originheader must match theHostthe request was sent to, so a page on another site cannot post to your ledger./apiis 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 forgeHostor terminate TLS inside your network, who is past this fence anyway. - Cookies follow the request. An auth cookie is marked
Securewhen 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.sqlplus copies of every uploaded file. PointingCONTINUUM_BACKUPSat 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=1seeds 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.
- 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.
- 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.