ParallelPathdocumentation

Security testing report

How ParallelPath has been tested, what was found, and what was fixed. Version 0.1.0-beta, October 2026. Testing was performed by the developer using automated and manual techniques; it is not an independent third-party audit.

Scope and method

Area Method
Application logic Automated end-to-end and attack test suite (app/tests/), run on every build
Source code Manual security code review of every route; static analysis with Bandit
Dependencies pip-audit against the PyPI/OSV vulnerability databases
Front end CSP compliance review (no inline script), stored-XSS injection into every text field
Deployment Review of systemd sandbox, AppArmor profile, nginx, coturn, database grants and triggers
Privacy Search of the whole code base and documentation for personal or identifying data; review of what each role and the admin can see

Testing follows the OWASP Top 10 (2021) categories.

Privacy checks

Automated tests that prove privacy promises, run on every build:

Check How it's tested Result
Encrypted at rest - database Known values (email, name, username, family name, child name, message subject/body, event title, file name) are written through the app; then the raw SQLite database file and its write-ahead log are scanned byte-by-byte (UTF-8 and UTF-16) None found in clear
Encrypted at rest - file store The same scan over every stored blob, including uploaded file contents None found in clear
IP addresses encrypted Raw database scanned for the client address Not found
Admins can't see family content Ten unique markers (message, private and shared file names and contents, journal, family/child names, expense, info bank) created by a family; every admin page, the analytics, metrics API and the audit CSV export are loaded and searched No marker appears anywhere
Admins can't see people's identities The same admin pages searched for the parents' usernames and emails Only masked forms appear; exact-match search confirms a person without revealing others
Admin audit redaction Admin audit page and CSV checked for family members' usernames Shown only as "family member"/"person"
No account takeover by admins An admin tries to reset a person's 2FA and obtain a reset link Refused until the person opts in; person notified and sees the action with the admin's reason
Admin session can't reach family routes Admin cookie used on messages, files, journal, expenses, info, reports, account and export Redirected to sign-in
Private space Other parent requests private files and journal entries by ID 404, and not listed
Parent's own encrypted export Export with passphrase decrypted with the documented format (PBKDF2-SHA256 + AES-256-GCM) Round-trips; short passphrases refused
No identifying data in published code or docs Release packaging scans every file for personal paths, keys and tokens; screenshots use fictional data only Packaging refuses on any hit

Plus, by design (verified in the deployment review): encryption at rest is mandatory (the app refuses to start unless its data is on an encrypted volume); web logs are anonymised and never record token-bearing URLs; remote AI providers must use HTTPS; backups contain only ciphertext.

Automated attack suite

40 tests in total, all passing (including the privacy checks above). Highlights:

OWASP Test Result
A01 Broken access control Every non-public route requested without signing in Redirected to sign-in
A01 IDOR: a user in another family tries to read 10 kinds of victim records (messages, events, files, private files, expenses, info bank, journal, reports...) All refused (404/403)
A01 ...and to change 10 kinds of records (retract a message, reply, edit an event, rename/copy a file, approve an expense, record a payment, edit info/journal, accept a swap) All refused; data unchanged
A01 The other parent tries to open private files and private journal entries Refused, and not listed
A01 A read-only professional tries to post, create events/expenses, invite people, start calls, and open areas they weren't granted All refused
A01 A family user tries every admin-portal page and action Redirected to admin sign-in
A01 Path traversal in the source viewer, static files and wiki Refused; no files outside the manifest readable
A01 Open redirect via next/page (//host, /\host, https://, javascript:) Only same-site paths accepted
A03 Injection Stored XSS payload in display name, family/child names, message subject/body, event title/location/notes, file name, expense title/notes, info-bank fields, journal, swap note - then 17 pages viewed by both parents Always escaped
A03 Uploaded HTML with script, requested for preview Forced download, nosniff, sandbox CSP
A03 SQL injection in every search/filter/sort parameter and sign-in No effect (parameterised queries)
A03 Spreadsheet formula injection in CSV reports Neutralised
A04 Insecure design Negative/zero/oversized expense and payment amounts Rejected
A04 Oversized upload Rejected (413)
A05 Misconfiguration Security headers and CSP on public and private pages; cross-site POST with foreign Origin, foreign Referer, missing origin, Sec-Fetch-Site: cross-site Headers present; all cross-site requests blocked
A07 Auth failures Brute force: sign-in, report verification, calendar-feed token guessing Rate-limited (429)
A07 User enumeration via sign-in responses Identical responses
A07 Session fixation (attacker-chosen cookie), cookie flags, re-use of a token after sign-out Ignored / HttpOnly+SameSite / rejected
A07 Admin and family portals use each other's accounts or cookies Refused
A08 Integrity Audit row altered directly in the database Detected by chain verification at the exact row
A08 Report with altered contents checked at /verify "No match"
A09 Logging Failed sign-ins logged for fail2ban; every action audited Verified
- Source publication secret-scanner given a file containing an API key Publication refused

Findings and fixes

# Finding Severity Status
1 cryptography dependency version allowed by the requirements had 4 published vulnerabilities (PYSEC-2026-3552/3553/3554, GHSA-537c-gmf6-5ccf) High Fixed - minimum version raised to 50.0.0; pip-audit now reports none
2 nginx regex location for sign-in pages took priority over /admin, so /admin/login would have bypassed the optional admin IP allow-list Medium Fixed - /admin uses a ^~ prefix location with the allow-list on every admin URL
3 Redirect targets accepted /\host, which browsers treat as another site Low Fixed - strict same-site path check (safe_next) + test
4 Expense edits and payments accepted zero/negative amounts Low Fixed - validated + test
5 Call-recording chunks had no per-call total size cap (authenticated disk-fill) Low Fixed - per-call part count, rate and 4 GB size caps
6 Audit verification could read cached database rows instead of stored ones Low Fixed - verification always reloads from the database + test
7 Embedded JSON on the call page didn't escape < Low Fixed - <, > and & escaped
8 Demo data used for documentation screenshots contained real-world place names, a phone area code and coordinates Privacy Fixed - replaced with fictional values (and mid-ocean coordinates); screenshots regenerated
9 An administrator could reset a person's 2FA / obtain a password-reset link and so sign in as them High (trust) Fixed - only with the person's opt-in; links emailed directly to the person; person notified + shown every admin action
10 The admin audit trail showed which person opened which record, their IP and profile changes Privacy Fixed - all person/family activity redacted for admins (view and CSV)
11 Admin account list and inbox showed people's usernames and emails Privacy Fixed - masked; exact-match search via encrypted index; inbox anonymous unless the sender opts in
12 Personal details (emails, names, IPs, devices, notification text) were plain columns inside the encrypted volume Privacy Fixed - now individually encrypted columns with a keyed blind index; raw-database scan test added
13 Full-volume encryption was optional Medium Fixed - mandatory in both installers; app refuses to start on an unencrypted volume
14 Web logs stored full IPs and token-bearing URLs (calendar feeds, invitations, resets) Privacy Fixed - anonymised addresses, no query strings/referrers, secret URLs not logged
15 A LAN AI provider could be configured over plain HTTP Medium Fixed - HTTPS required except for localhost
16 Admin settings page placeholder suggested a plain-HTTP AI URL Low Fixed

Static analysis (Bandit) reports no medium or high issues. Two low informational items were reviewed and are false positives (an empty-string comparison flagged as a "password", and XML-escaping used for PDF output rather than XML parsing).

Accepted risks / by design

Server-level testing

Performed on a fresh Ubuntu 24.04 LTS server after running the installer (and separately the Docker setup): TLS configuration scan, open-port scan, systemd sandbox exposure score, AppArmor enforcement, container hardening checks, database grant/trigger verification, encrypted-volume refusal test and HTTP header checks. Results are recorded below once completed for this release.

Server-level results: pending for 0.1.0-beta - see the release notes.

Re-running the tests

cd app
python -m pytest tests -n auto --dist loadfile      # functional + attack suite
python -m bandit -r parallelpath -ll                # static analysis
python -m pip_audit -r requirements.txt             # dependency vulnerabilities

Found something? Please report it privately - see Security.