Legal
Privacy policy
Effective 2026-05-26 · last updated 2026-05-27
Disclaimer. This document is a starting-draft privacy policy, not legal advice. Privacy law in Canada (PIPEDA, the proposed Consumer Privacy Protection Act, provincial laws including Quebec's Law 25, Alberta PIPA, and British Columbia PIPA) and abroad evolves quickly. Have a qualified privacy lawyer review and adapt this document for your business model, customer base, and jurisdictions before publication.
This Privacy Policy describes how Patrick A. Mikkelsen (the "Licensor", "we", "us", "our") collects, uses, discloses, and protects personal information in connection with Marginalia (the "Software"). It applies to two related but distinct settings:
- The Licensor's business. Information we collect from prospective and existing customers, support correspondents, and visitors to our website or product channels.
- The Software itself, as used by customers. Information processed by the Software when a customer (the "Licensee") deploys it inside their own organisation.
These two settings have different roles under privacy law, and we describe them separately so it's clear who is responsible for what.
1. Roles under privacy law
Marginalia is self-hosted software. The Licensee — typically a compliance / audit firm or a regulated organisation — installs and operates the Software on infrastructure they own or control. Under PIPEDA terminology:
- For information about the Licensor's own customers, the Licensor is the organisation subject to PIPEDA.
- For information processed by the Software in a Licensee's deployment, the Licensee is the organisation. We are at most a service provider with no routine access.
The Licensee should publish its own privacy notice covering the Software's processing in their environment.
2. Information we collect (Licensor)
2.1 Account and licensing information
- Name, business name, role
- Business email address, business telephone number
- Mailing or billing address
- Tax identifiers where required
- Number of seats / licensed Users, licence type and term
2.2 Payment information
Payments are processed by a third-party payment provider (currently Stripe, Inc.). We receive transaction confirmations and basic billing metadata; we do not receive or store full payment-card numbers.
2.3 Support correspondence
Email content, screenshots, attached log excerpts, diagnostic information you voluntarily share, and notes from support calls. If you grant us temporary access to your instance during a support engagement we may briefly see Customer Data; we treat it as the Licensee's confidential information and do not retain it.
2.4 Update telemetry (optional, opt-out)
If enabled: Software version, OS family/architecture, anonymous install identifier. No user identifiers, no Customer Data.
2.5 Website and product analytics
Standard server logs for site operation and abuse prevention. No third-party advertising or behavioural tracking.
2.6 Information you choose to provide
Newsletter signups, contact-form submissions, feedback, surveys.
3. Information the Software processes (Licensee)
3.1 Account information
- User email / username.
- Display name — encrypted client-side once the user has been migrated to encrypted state (see §3.6).
- Authentication verifier — a hash (Argon2id) of a client-derived authentication key, not of the raw password. The Software never sees a user's plaintext password.
- Session metadata: login times, IP address, user-agent.
- Theme preference, tutorial progress, approval state.
3.2 Customer Data (audit work product)
For users in encryption_state = 'encrypted', the
prose-bearing fields below are encrypted in the user's
browser before they reach the Software's server. The server
stores only ciphertext; the decryption key is held in the user's
browser session and protected by the user's password.
- Testing plans — name, title, jurisdiction, testing period, prepared-by, description, overall rating, additional notes, methodology JSON blob; all encrypted.
- Testing steps and substeps — descriptions encrypted.
- Observations — description encrypted; the
Note/Observation/Findingtype label stays plaintext server-side because it drives server-rendered colour coding and is a low-entropy 3-value enum. - Result notes and status — the prose note is
encrypted; the four-state status
(
pending/passed/failed/n_a/note) stays plaintext so the server can render progress counts and filter views. - Personal annotations — note and comment bodies encrypted; tag names encrypted (the server stores opaque placeholder strings for the uniqueness constraint).
- Citations of marked-testable provisions stay plaintext — they are used by the server for hierarchy, filtering, and cross-referencing. The auditor's prose attached to each citation is encrypted; the citation string itself is not.
3.3 Application logs
Request paths, timestamps, HTTP status codes, the logged-in user's numeric ID, errors and stack traces.
Request bodies are never logged for paths under
/auth/* (login, signup, password change, recovery, upgrade)
or for the encrypted curated-workbook export endpoint. Stack-trace
logging on those paths is body-redacted automatically by the global
exception handler.
3.4 Public legal text
The Software ingests Canadian federal Acts and regulations from public sources. This material is not personal information.
3.5 No access by the Licensor
Under default operation, the Licensor does not have any access to the Licensee's database, application logs, server memory, or Customer Data. The Licensee is the sole holder of the credentials, hashed authentication verifiers, and backups for its deployment.
3.6 End-to-end encryption (shipped)
The end-to-end encryption design is now in production. The high-level model:
- Account creation. At signup the user's browser:
generates two random 16-byte salts (
salt_auth,salt_kek) and a third (salt_recovery); derives an authentication key and a key-encryption key (KEK) from the user's password via Argon2id (m = 64 MiB, t = 3, p = 1, 32-byte output); generates a random 256-bit data-encryption key (DEK); wraps the DEK once under the password-derived KEK and once under a recovery-phrase-derived KEK (the 24-word BIP-39 mnemonic shown once during signup); sends only the authentication key, salts, KDF parameters, and the two wrapped DEKs to the server. The Software never sees the user's password, DEK, KEK, or recovery phrase in plaintext. - Storage. Wrapped DEKs are stored as BYTEA blobs;
the authentication verifier is
argon2id(auth_key). Every prose field listed in §3.2 is stored as AES-256-GCM ciphertext:[ version (1 byte) | iv (12 bytes) | ciphertext | gcm_tag (16 bytes) ]. - Sign-in. The browser fetches the user's salts
and KDF parameters (constant-time response shape — unknown emails
get deterministic synthetic salts so an attacker cannot enumerate
accounts), re-derives the authentication key + KEK, sends the
authentication key, unwraps the DEK, and holds it as a
non-extractable Web Crypto
CryptoKeyin a browser-only IndexedDB store for the session. - Reads. Server renders ciphertext to the browser
in
data-ctplaceholders; a client-side hydrator decrypts each via Web Crypto and replaces the DOM content. HTML payloads are sanitised through DOMPurify. - Writes. Forms with
data-encrypt="…"attributes encrypt named fields under the session DEK before POST. - Password change. The DEK value never changes — only its wrapper. The browser unwraps under the old KEK, re-wraps under the new KEK, and submits the new schedule atomically. Existing ciphertext stays decryptable.
- Recovery. A user who forgets their password can use their 24-word recovery phrase to unwrap the DEK, set a new password, and rotate to a fresh recovery phrase — all client-side. The server doesn't see the phrase.
- Excel export. Server cannot read encrypted prose; the browser decrypts every prose field locally, POSTs the decrypted payload to a dedicated endpoint, the server builds the workbook in memory, streams it back, and forgets the payload. Request bodies for this endpoint are not logged.
- Administrative password reset. Because the
Software does not have the user's password or recovery phrase, an
administrator cannot recover a user's encrypted
data. The administrator can reset a user's password
destructively — the reset wipes every encrypted column
the user owns; their pre-reset data is unrecoverable. The reset UI
requires the administrator to type
RESET <username>verbatim to confirm.
Cryptographic primitives are sourced from audited open-source
libraries (@noble/hashes for Argon2id, @scure/bip39
for the recovery phrase, DOMPurify for HTML sanitisation,
Web Crypto for AES-256-GCM). They are vendored into the Software with
Subresource-Integrity (SRI) hashes so the browser refuses to execute
any modified bytes. The Software does not load cryptographic code
from a CDN.
4. How we use information
We use the information we collect to provide, operate, maintain, and improve the Software; process payments and manage licences; respond to enquiries and provide support; send transactional messages; investigate and prevent fraud, abuse, and security incidents; and comply with legal obligations.
We do not sell personal information.
5. Legal basis (PIPEDA)
We collect, use, and disclose personal information for purposes that a reasonable person would consider appropriate in the circumstances, consistent with PIPEDA and its Schedule 1 principles (Accountability, Identifying purposes, Consent, Limiting collection, Limiting use, Accuracy, Safeguards, Openness, Individual access, Challenging compliance). Where Quebec's Law 25 applies, additional requirements may apply; the contact in §13 acts in that capacity.
6. Sharing and disclosure
- Service providers — payment processing (Stripe), email delivery, hosting (cloud providers in Canada/US). Each is required to use information only for the purposes we engaged them for.
- Legal disclosures — when required by law, court order, subpoena, or qualifying regulator/law-enforcement request. Where lawful, we notify the individual.
- Corporate transactions — merger, acquisition, bankruptcy, etc., subject to this Policy or equivalent successor terms.
- With consent — for any other purpose.
- Aggregate / de-identified — may share statistics that cannot reasonably be re-identified.
We do not share personal information with advertisers or data brokers.
7. Security
The Software supports:
- Argon2id authentication-key verifier — the Software stores
argon2id(auth_key)whereauth_keyis derived in the user's browser. The Software never receives the raw password. - End-to-end encryption of Customer Data prose fields (§3.6).
- CSRF protection, secure cookies, and HTTPS-only sessions in supported deployments.
- Subresource-Integrity on every vendored cryptographic file — the browser refuses to execute modified bytes.
- No CDN dependencies for cryptographic code — all crypto libraries are served from the same origin.
- Body-redacted logging on authentication and decrypted-payload endpoints.
No security measure is perfect. We will notify affected individuals and regulators where required by law of any breach creating a real risk of significant harm.
8. Retention
- Licensing and billing records: at least 7 years after the end of our business relationship.
- Support correspondence: up to 2 years.
- Update telemetry: anonymous; individual records discarded within 12 months.
- Marketing-consent records: duration of consent plus 2 years.
- Logs of administrative access: at least 1 year.
Customer Data processed by the Software inside a Licensee's deployment is retained according to the Licensee's policies, not ours.
9. Your rights
Subject to PIPEDA and provincial law, you have the right to access the personal information we hold about you, request correction of inaccurate information, withdraw consent (where consent is the basis for processing), and lodge a complaint with the Office of the Privacy Commissioner of Canada. Contact us at the address in §13.
10. International transfers
Our service providers may process information in Canada and the United States. We use contractual safeguards to require comparable protection.
11. Children
The Software is a B2B compliance / audit tool not directed to children. We do not knowingly collect information from children under 13.
12. Changes to this Policy
We may update this Policy from time to time. The effective date at the top of the document indicates when it was last revised. For material changes we will provide additional notice as appropriate.
13. Contact
For privacy enquiries, access requests, or complaints, contact:
Patrick A. Mikkelsen
[email protected]