bmersereau/mike

A security-minded Mike fork focused on safer document handling, access controls, and more dependable legal-AI workflows.

@bmersereau has tracked 84 distinct threads, with a last push on 2026-08-31, indicating recent and sustained attention despite no commits currently ahead of Mike.

View on GitHub →

bmersereau's Mike fork is currently aligned with Mike itself, but its surrounding work points to a clear product agenda: make a legal-document workspace safer to operate, easier to share reliably, and less fragile under real-world use.

The focus is practical hardening rather than a rebrand or a new niche. @bmersereau has concentrated on safer authentication and secret handling, protected uploads and downloads, privacy-conscious logging, and guardrails for chat, file storage, and bulk exports. Curious readers can follow the GitHub link for the implementation detail.

What's in it

Direction

securityinfrastructureworkflow

Activity

Themed changes and pull requests touching this fork, newest first. Themed changes that haven't been turned into a public post yet still appear — they're real work even without a published writeup.

📝 Add a PRD template for larger changes 1 commit 2mo ago minor change
Show 26 more
📝 Restore native Blob support in frontend tests 0 commits — minor change
📝 Make per-purpose secrets mandatory and enforce isolation at boot 0 commits — securityinfrastructure draft
bmersereau removes the silent fallbacks that let the download token signing secret and the user API key encryption secret quietly reuse the Supabase service key. Both secrets are now required, must be set explicitly, and…
📝 Add expiry to HMAC-signed download tokens, with 30-day default TTL 0 commits — securityinfrastructure draft
bmersereau proposed adding an `exp` Unix timestamp to every HMAC-signed download token and rejecting tokens past their expiry on verification. Legacy tokens without `exp` remain valid, so nothing breaks on deploy. The PR…
📝 Harden document uploads against XSS and tighten CSP 0 commits — securitycompliance draft
bmersereau's PR closes three separate security issues at once: stored XSS via malicious uploads, missing Content-Security-Policy headers, and unpatched `@xmldom/xmldom` CVEs. The core fix is magic-byte validation on both…
📝 Strip user and document IDs from edit-resolution INFO logs 0 commits — compliancesecurity draft
bmersereau opens a PR against upstream to remove INFO-level log lines in the edit-resolution handler that were emitting user identifiers, document identifiers, and edit identifiers alongside internal handler state - all …
📝 Fix timingSafeEqStr to run the comparison before checking length 0 commits — securityinfrastructure draft
The `timingSafeEqStr` helper guarding download tokens was short-circuiting on length mismatch before invoking the constant-time comparison underneath. That early return undermines the whole contract: an attacker with tim…
📝 Guard Supabase env vars in the backend 0 commits — minor change
📝 Hoist R2 S3Client to a module-level singleton 0 commits — infrastructureknowledge-management draft
The Mike backend was allocating a fresh `S3Client` on every R2 operation. bmersereau's PR hoists it to a module-level singleton with lazy initialization, so the HTTP layer can reuse keep-alive connections instead of reop…
📝 Singleton admin client in requireAuth middleware 0 commits — minor change
📝 Paginate GET /chat with limit and before-cursor parameters 0 commits — chat-uiinfrastructure draft
The `GET /chat` endpoint returns an unbounded list of a user's chats. bmersereau adds a `limit` parameter (default 50, cap 200) and a `before` ISO timestamp cursor, letting callers walk back through chat history one page…
📝 Add 180-second timeout to SSE chat streams via Promise.race 0 commits — chat-uiinfrastructure draft
bmersereau proposed wrapping the streaming LLM call in both chat routes with a `Promise.race` against a 180-second deadline. Stalled connections now emit a structured SSE error and close cleanly instead of hanging. The P…
📝 Convert user_id columns from text to uuid with FK constraints 0 commits — infrastructuremulti-tenant draft
Nine tables in the Mike backend carry `user_id` as plain text, with no referential link to the auth layer. bmersereau's PR converts all of them to the `uuid` type and adds proper foreign keys against `auth.users(id)`, wr…

Threads of work (detailed view)

19 threads have been distilled into posts.

Convert user_id columns from text to uuid with FK constraints

Nine tables in the Mike backend carry `user_id` as plain text, with no referential link to the auth layer. bmersereau's PR converts all of them to the `uuid` type and adds proper foreign keys against `auth.users(id)`, wrapped in a single transaction so the change is all-or-nothing.

Add 180-second timeout to SSE chat streams via Promise.race

bmersereau proposed wrapping the streaming LLM call in both chat routes with a `Promise.race` against a 180-second deadline. Stalled connections now emit a structured SSE error and close cleanly instead of hanging. The PR is open.

Paginate GET /chat with limit and before-cursor parameters

The `GET /chat` endpoint returns an unbounded list of a user's chats. bmersereau adds a `limit` parameter (default 50, cap 200) and a `before` ISO timestamp cursor, letting callers walk back through chat history one page at a time.

Hoist R2 S3Client to a module-level singleton

The Mike backend was allocating a fresh `S3Client` on every R2 operation. bmersereau's PR hoists it to a module-level singleton with lazy initialization, so the HTTP layer can reuse keep-alive connections instead of reopening sockets per request.

Fix timingSafeEqStr to run the comparison before checking length

The `timingSafeEqStr` helper guarding download tokens was short-circuiting on length mismatch before invoking the constant-time comparison underneath. That early return undermines the whole contract: an attacker with timing access could distinguish a length mismatch from a content mismatch.

Strip user and document IDs from edit-resolution INFO logs

bmersereau opens a PR against upstream to remove INFO-level log lines in the edit-resolution handler that were emitting user identifiers, document identifiers, and edit identifiers alongside internal handler state - all going to whatever log aggregator the deployment uses.

Normalize shared_with email casing across all project access paths

Project sharing in Mike was silently failing for users whose stored email casing didn't match the lookup. bmersereau traces the root cause to three different normalization rules scattered across four endpoints, extracts them into a single access module, and routes every project route through it.

Harden document uploads against XSS and tighten CSP

bmersereau's PR closes three separate security issues at once: stored XSS via malicious uploads, missing Content-Security-Policy headers, and unpatched `@xmldom/xmldom` CVEs. The core fix is magic-byte validation on both upload paths before a file is accepted.

Add expiry to HMAC-signed download tokens, with 30-day default TTL

bmersereau proposed adding an `exp` Unix timestamp to every HMAC-signed download token and rejecting tokens past their expiry on verification. Legacy tokens without `exp` remain valid, so nothing breaks on deploy. The PR is open against upstream.

Make per-purpose secrets mandatory and enforce isolation at boot

bmersereau removes the silent fallbacks that let the download token signing secret and the user API key encryption secret quietly reuse the Supabase service key. Both secrets are now required, must be set explicitly, and must be distinct from each other and from the Supabase key - enforced at startup before the server accepts any traffic.

Pull requests (detailed view)

23 PRs touch this fork — inbound (filed against it) or outbound (filed from it). State icons match the editorial dashboard.

🟢 Open (2)

✅ Merged (2)

⛔ Closed without merge (19)

Show 9 more closed