# Security policy ## Scope Scholion is local-first software that a single person runs on their own machine over their own medical data. There is no service, no account and no server we operate. In scope for a security report: - execution of arbitrary code or commands, including through a file name or a path taken from imported data; - reading, modification, deletion or disclosure of the local profile, genome or documents without an explicit action by the user; - transmission of personal data to the network that the user did not ask for — see `THREAT_MODEL.md` for the two lookups that do go out and what they carry; - vulnerabilities in the loopback web interface, including requests originating from another page open in the same browser; - unsafe parsing of an imported file: PDF, VCF, XML export, JSON; - packaging, release and supply-chain defects, including a published artifact that does not match the tagged source; - a defect that can silently corrupt a profile or leave an unsafe default. Out of scope as *security* reports, though we want to hear about them as ordinary issues: medical interpretation, a wrong threshold or a wrong direction of effect, support for a new laboratory or device, feature requests. Do not attach personal data to those either. ## Reporting a vulnerability **Do not open a public issue, pull request or discussion for a suspected vulnerability.** Use GitHub's private vulnerability reporting for this repository: 1. Open the repository's **Security** tab. 2. Choose **Report a vulnerability**. 3. Include the affected version, a minimal reproduction, the impact as you see it, and a suggested mitigation if you have one. If that button is not there, private reporting has been switched off by mistake in the repository settings. Open a normal issue saying exactly that — *"private vulnerability reporting appears to be disabled"* — and nothing else. Do not describe the vulnerability in it. **If you would rather not use GitHub at all**, write to scholion.dev@proton.me. The button is the better route — it keeps the report, the fix and the advisory in one place — but a report that reaches us by any means beats one that was not sent because the route felt wrong. Encrypt if you like: say so in the first line and a key will come back. **Response times.** This project is maintained by one person. We will not pretend to an SLA we cannot keep: expect an acknowledgement within a few days and an initial assessment once the report has been reproduced. If a report goes unanswered for two weeks, it has been missed rather than ignored — say so in a follow-up. When a fix ships, we publish a GitHub Security Advisory and coordinate the disclosure timing with the reporter. ## Never send personal health data A vulnerability report should demonstrate a *behaviour*, and behaviour reproduces on invented data. Real data in a report is a second incident. Do not attach or paste: - contents of `profile/`, backups, `assistant_context.txt`, or screenshots of the application showing real values; - VCF, BAM, FASTQ, genotype reports, sample or accession identifiers, or individual genetic findings; - laboratory PDFs, clinical reports, prescriptions, Garmin or Apple Health exports, or unredacted logs; - API keys, passwords, tokens or cookies. Use the synthetic demo profile — `scholion init --demo` builds a complete, fictional person in one command — or a minimal hand-made file. Replace names, dates of birth, addresses, accession numbers, URLs containing identifiers, and every measurement. If a reproduction genuinely requires a real file, say so in the report and wait. Do not send it first. ## The author's own data in this package An outside audit of v2.19.0 decoded a list of the author's identifiers out of `src/tools/make_shareable.py` and read it back to us. They were base64-encoded, and the comment beside them said why: so that the script — which ships inside the package, because it IS the build procedure — would not fail its own audit. That audit compares substrings, and an encoded string is a substring of nothing. The check reported clean on a file carrying exactly the data it exists to stop. Eleven identifiers travelled that way: a surname in two alphabets, an e-mail handle, a date of birth, a sample number, a GitHub account, a home path. One line of Python reversed them. **They are gone from v2.20.0 onward**, and not by being documented. The list is read at build time from `.personal_patterns`, a file next to the project that is in `.gitignore` and never ships. A build that cannot find it stops rather than reporting a package it could not check; a fork with no owner data to protect says so with `--no-personal-patterns` and is told in the output that the package went out unchecked. And the audit now decodes base64 literals in text files and searches the decoded text too — so the next identifier encoded for the same well-meant reason is caught by the rule that failed here. **What remains, deliberately, is one identifier in two files:** | Where | What | Why it stays | |---|---|---| | `NOTICE` | the copyright holder's name | Apache-2.0 requires the notice; without it the licence grant is unclear | | `CITATION.cff` | the author's name | it is citation metadata — that is what the file is for | Both are covered by a named exception in `src/tools/check_staged.py`, and that exception is itself pinned: `tests/test_privacy_guard.py` asserts by function signature that it cannot be widened by file name. Nothing else of the author's is in this package, in any encoding — `tests/test_build_audit.py` checks both forms against the machine's own pattern list. If you want a fully anonymous mirror, fork and replace `NOTICE` and `CITATION.cff` with your own. ## Supported versions Fixes are made against the latest released version. Where a fix also applies to an earlier release, the advisory names the exact fixed version and any available mitigation. There is no long-term support branch. ## What we will not do We will not ask you for credentials to any external service, and the assistant layer will not accept or enter them either — that rule lives in `ASSISTANT-RULES.md`, which comes first among this project's documents. A message asking you for a password "to check something in Scholion" did not come from this project.