Security
What ControlLedger does to protect accounts, files and records, stated plainly.
Accounts
- Passwords are hashed with scrypt (N=32768, r=8, p=1) and a random 16-byte salt. They are never stored or logged in clear text.
- Passwords must be at least 10 characters, must not appear on a list of 1,000 common passwords, and must not contain your email address.
- Sessions are server-side and revocable. The cookie is HttpOnly, SameSite=Lax and, in production, Secure with the
__Host-prefix. Sessions expire after 30 days of inactivity and can be ended from Security. - Sign-in is limited to 10 attempts per minute per IP address and 20 per hour per email address.
- Email verification and password reset links are single-use, expire (24 hours and 30 minutes), and are stored only as hashes.
Tenancy
Every table that holds customer data carries the account id, and every query filters by it. Object ids are random and unguessable, but access never relies on that: a request for another account's object returns "not found".
Files
- Uploads are accepted only when their content matches an allowed type (PNG, JPEG, WebP, PDF, CSV, text, EML, XLSX), regardless of file name.
- Files are stored under generated names outside the web root, at most 10 MB each, and are served only through authenticated or tokenized routes. Non-image files are always delivered as downloads; uploaded HTML is never rendered.
- The SHA-256 of every file is recorded on arrival and printed in evidence PDFs.
Evidence files and retention
- Evidence attached to an attestation may contain client-sensitive screenshots and exports. Files are served only to signed-in users of your account, to a client contact through a single-use co-sign link, or through an expiring read-only share link that you can revoke. Every download through a link is recorded with time and IP address.
- Retention is yours to set in Settings: keep files until the client is archived, or delete them after 1, 2, 3 or 7 years. Archived clients' files are hard-deleted 30 days after archiving. Attestations and file hashes are always kept, so a pack generated earlier stays verifiable.
- Co-sign links are 32 random bytes, stored hashed, valid for 14 days, single use and scoped to one attestation.
Records and Evidence Packs
- Events are chained per account with SHA-256; the chain can be verified at any time and a break is reported, not hidden.
- Evidence Packs print the chain head at generation time and carry an integrity page with the SHA-256 of the document body. The file hash is recorded in the chain so it can be checked on the public verify page.
- A pack records attestations made by your account. It does not verify them, does not claim compliance, and is not legal, insurance or audit advice.
Transport and browser
- All traffic is served over HTTPS with HSTS. Requests arrive through Cloudflare.
- A strict Content Security Policy allows scripts and styles only from this origin, forbids inline scripts and framing, and restricts where forms may submit.
- Every state-changing request carries a per-session CSRF token and must originate from this site.
- Requests are rate limited (300 per minute per IP; 10 per minute on sign-in and token endpoints).
Operations
- Logs contain request ids, paths and timings. They never contain passwords, session ids, tokens or file contents.
- The database is backed up nightly; backups are kept for 14 days.
- Payment details are handled by Stripe through the InfiniHash App Store. ControlLedger never sees card numbers.
Reporting a problem
If you believe you have found a security issue, email [email protected] with "security" in the subject. We acknowledge reports within two business days and do not pursue researchers who act in good faith.