Security

What we encrypt, what we don't store, and how to verify.

LinkSilo's privacy posture is defined by what reaches our servers as ciphertext, what reaches our servers not at all, and what reaches our database under role-restricted access only. This page describes the security model, the cryptographic primitives in use, and the procedures by which independent parties verify both.

Last reviewed 2026-05-11

Scope

What "security" means on this page.

Security claims on this page refer to four concrete properties: (1) data encrypted in the user's browser before transmission, (2) data stored at rest under role-restricted database access, (3) data in transit over hardened TLS, and (4) data we deliberately do not collect. Each claim is mapped to specific code paths in our open-source repository, with privacy-sensitive routes flagged for security review at merge time.

Threats explicitly in scope: external network attackers, database compromise of LinkSilo infrastructure, mass surveillance by hosting-provider personnel, and adversarial third-party services. Threats explicitly out of scope: compromise of the user's own device or browser, attacks against the user's password by a party with that password, and physical access to an unlocked session.

Browser-side cryptography

Encryption performed in the user's browser, before transmission.

The following primitives are used for data that must remain confidential to the user. Key derivation, symmetric encryption, and public-key encryption all execute in the browser via the RustCrypto crate family compiled to WebAssembly. The server never holds the plaintext for any data protected under these flows.

XChaCha20-Poly1305-IETF

Symmetric authenticated encryption with associated data (AEAD). 256-bit key, 192-bit nonce. The extended nonce length provides sufficient margin for random nonce generation without the structural pairing required by AES-GCM, eliminating a class of nonce-reuse failures observed in deployed AES-GCM systems.

Argon2id

Password-to-key derivation. Minimum parameters m=64MB and t=2. Parameters are recalibrated against current commodity GPU capacity. The derived key never leaves the user's browser.

X25519 sealed-box

Anonymous public-key encryption used for visitor-to-creator messages. The visitor encrypts to the creator's published X25519 public key without revealing or generating a persistent sender identity.

Ed25519

Digital signatures. Used for service-to-service trust within the platform and for signed audit-log entries.

BIP-39 recovery phrase

A 24-word phrase generated at signup, displayed once to the user, and used as the sole recovery mechanism if the password is lost. The recovery flow does not bypass encryption; the phrase derives a key that decrypts the wrapped master key.

RustCrypto

The pure-Rust cryptographic crate family underlying all of the above (chacha20poly1305, crypto_box, ed25519-dalek, argon2, hmac, hkdf). LinkSilo pins audited versions and does not implement primitives internally.

At rest

Encrypted ciphertext, role-restricted database access.

User-generated content is stored as ciphertext blobs that LinkSilo cannot decrypt. Database access is partitioned across PostgreSQL roles, each granted the minimum privileges required for its service.

Page content
Page titles, link labels, link URLs, and social URLs are encrypted in the user's browser under the user's master key before submission. The server stores ciphertext only. The public renderer service reads ciphertext and serves it to the visitor's browser, which decrypts client-side.
Newsletter subscribers
Subscriber email addresses are sealed-box encrypted in the subscriber's browser. The server stores ciphertext plus an HMAC-based dedup hash. Server-side dedup is possible; server-side decryption is not.
Renderer role
The public renderer service connects to PostgreSQL under a read-only role with SELECT privileges restricted to the columns required for rendering. The role cannot write to any table or read API keys, sessions, or admin tables.
Ingress role
The analytics ingress service has no PostgreSQL access. It forwards coarsened beacon data to the aggregator over an internal RPC channel; the aggregator owns DB writes.
In transit

Hardened TLS, single implementation, rustls only.

All transport encryption uses rustls; no OpenSSL sits in any TLS path. OpenSSL is present only as a transitive dependency of the WebAuthn/passkey library, where it parses attestation certificates -- never for transport security or the browser-side cryptography above. The single-implementation TLS posture reduces the attack surface introduced by parallel TLS stacks with different defaults, vulnerability histories, and configuration shapes.

TLS 1.3 with hybrid post-quantum key exchange (X25519MLKEM768) is enabled by default on the production edge once the deployment's certificate-authority pipeline supports it. Certificate transparency monitoring is enabled for all LinkSilo hostnames.

What we don't collect

Data the ingress edge drops before any database write.

The analytics ingress receives certain inputs out of necessity (an HTTP request carries the visitor's IP and User-Agent), then coarsens and discards them at the process boundary. The list below describes data that is never written to a LinkSilo database under any tier or configuration.

IP addresses
The ingress receives the visitor's IP, derives a country code via MaxMind GeoLite2, computes a daily-salted HMAC for unique-visitor counting, and discards. No log line writes the raw IP to disk. Tracing layers in the ingress redact IP from request scope.
User-Agent strings
The User-Agent is mapped to one of four device classes (desktop / mobile / tablet / other) at ingress. The raw string is discarded. The classification cannot be reversed to reconstruct the original UA.
Referer URLs
The HTTP Referer header is mapped to one of five referrer classes (direct / internal / external / social / search). Pro and Premium tiers additionally store a 2-character mnemonic drawn from a hard-coded whitelist of well-known platforms. The full URL — including any UTM parameters or session IDs from the referring site — is discarded.
Cross-day visitor identity
The HMAC salt rotates every 24 hours UTC. A visitor returning the next day produces a different hash and is counted as a fresh unique visitor. Cross-day uniqueness is not computable from stored data.
City-level geography
Country code only. City-level geolocation can re-identify single visitors in low-population countries; LinkSilo does not collect at that resolution.
Server-side AI inference
No server-side machine-learning inference is performed over user content. Server-side AI access to encrypted-at-rest data would require server-side decryption, which is not present in the architecture.
Analytics privacy

Aggregate counters, k-anonymity thresholds, daily-rotating salt.

Analytics data is aggregated rather than per-event. Visitor-derived dimensions are subject to k≥5 suppression at the API layer: dimensions whose population falls below the threshold within the query window are collapsed into an "other" bucket with the sum preserved.

Visitor identity
HMAC-SHA256 of (IP + User-Agent) keyed by a server-side salt that rotates every 24 hours UTC. 8-byte truncation. The salt is generated from /dev/urandom and stored only in the ingress process memory for its 24-hour active window.
Country mix
Countries with fewer than 5 visitors over the query window collapse into "other". The total sum is preserved; per-country counts are revealed only above the threshold.
A/B variant splits
Both variants of a given link must have ≥5 clicks for the split to render. Below threshold, the entire link's variant data is omitted.
Hour-of-day patterns
Computed from hourly bucketed data summed across the full query window. The coarsening makes single-visitor temporal re-identification infeasible.
Tip funnel counters
Per-page-per-UTC-day counters (page views, initiated, completed) plus per-currency completed sums. No per-visitor data, no per-transaction details, no payment information.
External review

Independent verification, planned before public launch.

LinkSilo treats internal claims about cryptography and privacy as provisional until verified by independent parties. The following independent reviews are planned.

Pre-launch cryptographic review
We plan to commission an external cryptographer to review LinkSilo's cryptographic primitives, key-derivation paths, and master-key flow before public launch, and to publish the resulting report.
First-year penetration test
We plan to commission a third-party penetration test of the LinkSilo production environment within the first year of operation, with subsequent tests intended annually. Summary findings would be published in the annual transparency report; detailed findings remediated before publication.
Annual transparency report
A transparency report is published once per calendar year, covering government data requests received, account terminations by category, security incidents disclosed, and external-review findings remediated.
Source-code inspection
Client code is published under AGPL-3.0 from the public launch onward. Server code is published under AGPL-3.0 within 12 months of the public launch. Anyone may inspect the implementation directly against the claims on this page.
Vulnerability disclosure

Coordinated disclosure, bounty by severity.

Security researchers are invited to report vulnerabilities under a coordinated disclosure process. The intake address and the bounty schedule are listed below; both are also mirrored in the repository's SECURITY.md.

SeverityBounty rangeExamples
Critical€1,000 – €2,000RCE, master-key extraction, account-takeover via authentication bypass
High€500 – €1,000Server-side decryption oracle, persistent privilege escalation, sensitive-data leak via direct DB access path
Medium€100 – €500CSRF on state-changing endpoints, persistent XSS in creator-only views, broken access control on a limited resource
Low€50 – €100Reflected XSS in a low-impact context, missing security header on a non-state-changing route, information disclosure of non-sensitive metadata

Reporting

Email with a description of the issue, reproduction steps, and your assessment of the impact. PGP encryption is strongly preferred; the public key will be published at https://linksilo.io/.well-known/pgp-key.asc (at launch; not yet available) and rotated every 24 months.

Response timeline: acknowledgment within 72 hours during business days. Initial assessment within 7 days. Status updates through resolution. Public credit in the security advisory unless anonymity is requested.
Open source

Source code is published. Verification is by inspection.

LinkSilo's client-side code is published under the GNU Affero General Public License v3.0-or-later (AGPL-3.0) from the public launch onward. Server-side code is published under the same license within 12 months of the public launch. The repository lives on Codeberg, mirrored to a Finnish-incorporated source forge to keep the canonical copy under EU jurisdiction.

Privacy-sensitive code paths are tagged with a PRIVACY: comment marker. Any merge request that touches a tagged path is flagged for security review at merge time.