Ufraan's Notes Digital garden & personal knowledge base
Last modified: Jun 28, 2026Home / 07_ideas / # Slerim — Zero Knowledge Github Backups.Md

Your repos, encrypted before they ever leave your browser. The server never sees your data.


The Problem

Most developers don’t back up their GitHub repos. They assume GitHub won’t go down, that their account won’t get suspended, that they won’t accidentally git push --force the wrong branch. Until one of those things happens.

Slerim solves this by letting you schedule encrypted backups of your GitHub repositories to cloud storage — with a zero-knowledge guarantee baked into the architecture, not bolted on afterward.


Core Idea

Slerim is a GitHub backup service where the encryption key is generated entirely in your browser, split using Shamir’s Secret Sharing, and never stored whole on any server. The server handles scheduling, cloning, and storage — but it only ever sees ciphertext. Not even the session key used to encrypt a backup is stored in plaintext.


How It Works

Onboarding

You fill out a signup form. The browser immediately generates a K2 keypair using Argon2id KDF, derived from your master password and email. The private key never leaves your device. The public key is sent to the server.

The K2 private key is then split into 3 Shamir shares with a threshold of 2:

Any 2 of 3 shares reconstruct K2. The server alone, holding only share 3, cannot reconstruct anything.

During onboarding you also provide and verify a mandatory backup email. This is not optional. It serves two purposes: it receives share 2 of your Shamir split, and it is your fallback identity if you ever lose access to your primary account. If your GitHub gets suspended and your Google account gets compromised, you can still authenticate via this email and reach your backups.

Backup Job Pipeline

A backup is triggered on schedule or manually. The job enters a Postgres-backed queue (SELECT FOR UPDATE SKIP LOCKED — no Redis needed). The worker picks it up, fetches your encrypted GitHub OAuth token, and decrypts it in memory only.

The worker clones your repo from GitHub, generates a fresh random symmetric key K, encrypts the repo tarball with K using AES-256-GCM, then encrypts K itself with your stored K2 public key. Both the encrypted backup and the encrypted K go to Cloudflare R2. The server never holds K or K2 in persistent storage.

Once the backup lands in R2, a single-use download token is generated (slerim.com/download?t=xyz) and Resend delivers it to your backup email as a clean URL.

Download and Restore

You click the link from your email. The /api/download endpoint validates the token — checking it hasn’t expired and hasn’t already been used. If either check fails, you get a 403 or 410. If valid, the token is immediately marked used (single-use enforced), a presigned R2 URL with a 1-hour expiry is generated, and you are 302-redirected to it. R2 serves the bytes directly to your browser. The server is out of the data path from this point forward.

Your browser downloads the zip containing enc_backup and enc_K. You provide your K2 private key (offline, from share 1 or reconstructed via any 2 Shamir shares). The browser decrypts enc_K using K2, then decrypts the backup using K. You get a bare git clone. From there: git push --all --tags to your new account.


Key Properties

Zero-knowledge — K2 is generated client-side via Argon2id. The private key never leaves the browser. The server stores only the public key, share 3, and ciphertext.

Auth independence — Google SSO means a GitHub lockout does not lock you out of Slerim. The verified backup email goes further: it is a parallel identity that survives both a GitHub suspension and a Google account compromise. Neither fallback is a convenience feature — both are load-bearing parts of the recovery story.

Shamir’s Secret Sharing — K2 is split 3 ways, threshold 2. Any two shares reconstruct the key. The server holding share 3 alone cannot reconstruct K2 — a server breach does not expose your private key.

Envelope encryption — Each backup is encrypted with a fresh random K. K is then encrypted with your K2 public key. K2 rotation does not require re-encrypting every backup — only the stored enc_K values need updating.

Single-use download tokens — Download links expire and are marked used on first redemption. Replaying a link returns a 410.

No Redis — The job queue is Postgres-backed using SELECT FOR UPDATE SKIP LOCKED. One less moving part.

Idempotent jobs — If a backup job fails mid-run, the retry does not create duplicate records, re-clone unnecessarily, or double-charge. Job state is tracked explicitly in the backup_jobs table.


Architecture

Onboarding Flow

slerim-onboarding-flow.png

User Browser
    └─→ Signup Form
            └─→ Client-Side Key Gen (browser only)
                    └─→ Argon2id KDF (master password + email)
                            ├─→ K2 Private Key (never leaves device)
                            │       └─→ Shamir Split (3 shares / threshold 2)
                            │               ├─→ Share 1 — user saves offline
                            │               ├─→ Share 2 — sent to backup email
                            │               └─→ Share 3 — stored on server
                            └─→ K2 Public Key (sent to server)
                                    └─→ Server DB stores: K2 pub, share 3, enc GitHub token

Mandatory backup email verified at onboarding via time-limited signed token.

Backup Job Pipeline

slerim-backupjob-pipeline.png

Trigger (scheduled / manual)
    └─→ Job Queue (Postgres: SELECT FOR UPDATE SKIP LOCKED)
            └─→ Worker: fetch enc GitHub token, decrypt in memory
                    └─→ GitHub API: clone repo bytes
                            └─→ Encryption Step
                                    ├─→ Generate random symmetric key K
                                    ├─→ Encrypt repo tarball with K (AES-256-GCM)
                                    └─→ Encrypt K with K2 public key
                                            └─→ Cloudflare R2: store enc_backup + enc_K
                                                    └─→ Generate single-use download token
                                                            └─→ Resend → backup email inbox

KEY RECOVERY: any 2 of 3 Shamir shares reconstruct K2.
The server holding share 3 alone cannot reconstruct.

Download and Restore

slerim-download-and-restrore.png

User clicks email link
    └─→ /api/download: validate token
            ├─→ expired or already used → 403 / 410
            └─→ valid
                    ├─→ mark token used (single-use enforced)
                    ├─→ generate presigned R2 URL (1hr expiry)
                    └─→ 302 redirect to R2 URL
                            └─→ R2 serves zip directly to browser (server not in data path)

Client-side restore:
    User provides K2 private key (offline / reconstructed from shares)
    Browser: K2 decrypts enc_K → K decrypts enc_backup → bare git clone
    └─→ git push --all --tags to new GitHub account

Tech Stack

Layer Choice
Frontend Next.js (App Router) + Tailwind + shadcn/ui
Auth Better Auth (Google SSO + backup email verification)
Database PostgreSQL + Drizzle ORM (Neon)
Job Queue Postgres (SELECT FOR UPDATE SKIP LOCKED)
Storage Cloudflare R2 (presigned URLs, envelope encryption)
Runtime Bun
Encryption AES-256-GCM + Argon2id KDF
Key Management Shamir’s Secret Sharing (3 shares, threshold 2)
Email Resend (backup delivery + email verification)
Error Tracking Sentry
Logging Axiom (structured logs, queryable)

Threat Model

The server is treated as compromised by default.

What Slerim does not protect against: a compromised browser environment, malware on the client machine, or a user who stores their offline share insecurely. Client-side encryption shifts the trust boundary — it does not eliminate it.


Observability

Structured logs on every backup job — who triggered it, which repo, duration, success or failure reason. Log level system (info / warn / error). Logs shipped to Axiom, queryable after the fact.

Error tracking via Sentry. When something breaks at 2am for a user, you need a stack trace with context, not a generic failure email. Free tier is sufficient through V1 and V2.

Minimum metrics tracked: backup job success rate, job queue depth, R2 storage per user, download token redemption rate. Without these you are flying blind when something degrades slowly rather than failing loudly.


Roadmap

Pasted image 20260320053944.png

V1 — MVP

Prove the core loop works.

Not in V1: encryption, scheduled jobs, backup email, Shamir, rate limiting, Resend.

The only question V1 answers: does the backup-and-restore cycle work end-to-end?

V2 — Usable Product

Safe enough for real users.

Not in V2: Shamir split key, billing, API access.

V2 is the version you show people and ask them to actually use.

V3 — SaaS Product

Monetisable, defensible, honest zero-knowledge claim.

V3 is only built after V2 has real users who trust it. Do not build V3 features before V2 is validated.


Open Questions