Security

Security at BlockAlt

How the service is built, what we keep and for how long, and how to report a vulnerability. This page describes the code of the current release; the changelog lists what is already deployed.

Data handling

What we keep, and for how long

Everything BlockAlt records about your visitors, with its retention. Errors are logged without request bodies, tokens, secrets or IP addresses.

DataWhat it holdsKept for
Protection eventsThe site, the outcome, the reason and the time. They never contain raw IP addresses, tokens, secrets or request bodies.7 days
Refusals of tokens we did not issueForged, malformed, empty, expired or another site's tokens get no event: they are counted per site, minute and reason.7 days
Rate-limit countersPer visitor network (an IPv4 address or an IPv6 /64) in short-lived counters held in memory; counters kept in the database use keyed hashes (HMAC-SHA-256 with a server secret), never the address. They never reach logs or events.Minutes
Consumed tokens and challengesRandom identifiers only, to stop replays.Until an hour after they expire
Cryptography

Tokens, signing and secrets

Which keys protect what, and how every secret is kept at rest.

Tokens and challenges

  • Authenticated with HMAC keys derived on the server and identified by a key id, so they can be rotated without touching customer pages.
  • Challenges expire after 90 seconds and tokens after 120 seconds. Each works once.
  • Bound to the site, hostname, action and published configuration version; the server re-checks every claim at verification.
  • Each token carries a per-token keyed hash of the network that solved it, checked when your server sends remoteip.

Signed, pinned configuration

  • The browser script is served under a content-addressed URL that you pin with Subresource Integrity.
  • It accepts site configuration only when it is signed (Ed25519, or P-256 for browsers without Ed25519) by a key you pinned in your page.
  • Standby keys allow rotation without breaking installs. Those keys sign configuration only.

In transit and in webhooks

  • All traffic uses TLS, with HSTS on every public page.
  • SIEM notifications are signed with HMAC-SHA-256 over a timestamp and the raw body, using a per-endpoint secret shown once, so receivers can refuse replays.

How each secret is kept

Hashes where we only need to compare; encryption where the value must be read back.

Passwords
Hashed with Argon2id. New passwords are checked against known breaches with the Have I Been Pwned range API: only the first 5 characters of the password's SHA-1 hash leave our servers.
Site secret keys
Shown once and stored as SHA-256 hashes; revoking one takes effect on the next verification.
Sessions, emailed links and API keys
Session cookies, sign-up, password-reset, email-change, deletion and invitation links and management API keys are stored only as hashes.
Recovery codes
Stored as keyed hashes (HMAC-SHA-256 with a server secret).
Passkeys
Stored as public keys.
Authenticator secrets, webhooks and queued email
Authenticator (TOTP) secrets, notification webhook URLs and signing secrets, and queued email are encrypted with AES-256-GCM, each sealed to its own record.
Infrastructure

How the service is built

Where BlockAlt runs, and what it is deliberately not.

Not in your traffic path

BlockAlt is not a proxy. Three separate conversations, and only the last two involve us:

  1. Your visitorsyour serversPages, forms and data. BlockAlt never sees this traffic.
  2. Browser scriptBlockAlt APISigned configuration, a challenge, and a single-use token.
  3. Your backendPOST /v1/siteverifyOne call per action, with your secret key.

Deliberately absent: visitor analytics, fingerprinting, session replay and cross-site identifiers.

Where it runs

Location
A dedicated virtual machine in Helsinki, Finland (Hetzner).
Software
One API process and one worker, written in TypeScript on Bun, with PostgreSQL.
In front
Cloudflare DNS and TLS proxying, and a TLS reverse proxy on the host. The host's reverse proxy logs no visitor addresses or URLs.

Containers

  • Every container has a read-only root filesystem and cannot gain privileges.
  • The API, worker and migration containers run as a non-root user with all Linux capabilities dropped.
  • PostgreSQL runs as its own unprivileged user with no capabilities (its start-up script keeps only the four it needs to hand the data directories to that user) and sits on a private network without a public port.
Accounts and access

Account security

Every workspace is managed with two factors, short sessions and an audit log.

Backups and recovery

  • Encrypted dumps

    Database backups are consistent dumps encrypted with age together with the matching keys, so a restore can open MFA secrets and verify signatures.

  • Restores rehearsed

    Restores always target a new, isolated database. The encrypted restore is rehearsed automatically in continuous integration.

  • Objectives being measured In progress

    Off-site replication, backup frequency and recovery objectives for production are being validated before general availability; we will publish them here once measured.

Public pages

This site sends a strict set of security headers on every page:

  • Content-Security-Policy without inline scripts, with Trusted Types enforced
  • Strict-Transport-Security (HSTS)
  • frame-ancestors 'none'
  • Cross-Origin-Opener-Policy and Cross-Origin-Resource-Policy
  • A restrictive Permissions-Policy

The public pages set no cookies and run no inline script.

Responsible disclosure

Report a vulnerability

Email support@blockalt.click with the affected URL or component, the steps to reproduce, what an attacker could achieve, and how to reach you. Never include another customer's data, and never send a site secret key: rotate it in the console instead.

We acknowledge every report, keep you informed while we fix it, and credit you on the changelog if you wish. There is no paid bug bounty at the moment.

The same contact, machine-readable, in /.well-known/security.txt:

security.txt
Contact: mailto:support@blockalt.click
Expires: 2027-05-08T00:00:00.000Z
Preferred-Languages: en
Canonical: https://blockalt.click/.well-known/security.txt
Policy: https://blockalt.click/security#disclosure

Safe harbour

If you act in good faith and follow these rules, we will not pursue legal action against your research:

  1. Test only against accounts, workspaces and sites you own. Stop and tell us as soon as you reach data that is not yours, and do not keep it.
  2. Do not run denial-of-service or high-volume tests, spam, social engineering or physical attacks. Proof-of-work cost, rate limits and the documented limits of the product are not vulnerabilities on their own.
  3. Give us reasonable time to fix the issue before you publish, and coordinate the date with us.