You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Admin panel auth: ADMIN_TOKEN env var protects /__admin/* routes
- Admin password: moved hardcoded Elixir@2025! to ADMIN_PASSWORD env var
- Admin email: moved hardcoded email to ADMIN_EMAIL env var + redaction in verify HTML
- Rate limiting: 10 req/min/IP on /__auth/signup + /__auth/login
- SW cache: add Auth-*.js + useInvites-*.js to network-only bypass list
- Body limit: readReqBody() now enforces 1 MB max
- Backfill: startup queries raised from LIMIT 500 to LIMIT 2000
- package.json version corrected 1.1.3 → 2.3.0
- Docs: CHANGELOG, AUDIT, AGENTS, WORK_LOG updated
**Where to get Supabase keys:** Supabase Dashboard → Project Settings → API
50
53
54
+
**Security note (v2.3.0+):**
55
+
- Set `ADMIN_TOKEN` before any public deployment to lock down `/__admin/*` endpoints.
56
+
- Set `ADMIN_PASSWORD` to a strong unique password — the default is intentionally not secret.
57
+
-`ADMIN_EMAIL` controls which email the auto-created admin account uses and which email the verify check looks for.
58
+
51
59
---
52
60
53
61
## How `server.mjs` patches work
@@ -176,7 +184,7 @@ This was extracted directly from the compiled JS bundles. **Do not guess column
176
184
### 2. service_role key is used for all community API calls
177
185
**Why:** Community tables have RLS enabled. The service_role key bypasses all RLS without needing per-user auth headers on the server side.
178
186
**How:** The `/__supa/*` proxy adds `Authorization: Bearer {SUPA_SERVICE_KEY}` and `apikey: {SUPA_SERVICE_KEY}` to every proxied request.
179
-
**Warning:**Never expose the service_role key in client-side code.
187
+
**Warning (v2.3.0 updated):**The service_role key is also injected into the `App-pJGjDiPw.js` bundle (see `getPatchedAppBundle()`), meaning it is delivered to every browser. This is intentional for self-hosted/trusted-user deployments. Do NOT run this server for public multi-tenant apps with untrusted users.
180
188
181
189
### 3. Bundle patches are in-memory only
182
190
**Why:** Modifying the built JS on disk would make the diff unreadable and break future updates.
@@ -300,17 +308,22 @@ functions\.invoke\("([^"]+)" — edge function names
Copy file name to clipboardExpand all lines: AUDIT.md
+10-1Lines changed: 10 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -358,7 +358,7 @@ useEffect(() => {
358
358
359
359
### What is safe to commit
360
360
- All bundle files in `public/assets/` — these are client-side JS, already public on isotopeai.in
361
-
- `server.mjs` — no secrets hardcoded (all keys via env vars)
361
+
- `server.mjs` — no secrets hardcoded (all keys via env vars or configurable defaults)
362
362
- `isotope-schema.sql` — no credentials
363
363
- All scripts, Dockerfile, README, AUDIT
364
364
@@ -372,6 +372,15 @@ The anon key (`eyJhbGci...`) visible in `server.mjs` is the **public anon key**
372
372
### The service_role key
373
373
This is never hardcoded. It must be provided via `SUPABASE_SERVICE_ROLE_KEY` environment variable. It bypasses all RLS — treat it like a database root password.
374
374
375
+
### Admin panel endpoints (v2.3.0+)
376
+
`/__admin/*` routes are protected by an optional `ADMIN_TOKEN` env var. If set, all admin requests must include the token via `X-Admin-Token` header or `?token=` query param. Without the token configured the panel is open — acceptable for local/Replit dev but **lock it down before any public deployment**.
377
+
378
+
### Admin password (v2.3.0+)
379
+
The admin account password is read from `ADMIN_PASSWORD` env var (default: `IsotopeAI@2025!`). Override this before deploying. The old hardcoded password `Elixir@2025!` has been removed from source code.
380
+
381
+
### Service-role key in App bundle (by design)
382
+
`getPatchedAppBundle()` injects `SUPA_SERVICE_KEY` into `App-pJGjDiPw.js`. This means the service-role key is delivered to **every browser that loads the app**. This is an intentional architectural choice for self-hosted deployments where all users are trusted and RLS bypass is needed globally. If you are running a multi-tenant public deployment with untrusted users, do NOT use this server — the service_role key gives full read/write access to all Supabase data, bypassing all RLS policies.
Copy file name to clipboardExpand all lines: CHANGELOG.md
+19Lines changed: 19 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,25 @@ All notable changes to this project are documented here.
4
4
5
5
---
6
6
7
+
## [2.3.0] — 2026-06-01
8
+
9
+
### Security
10
+
-**Admin panel protection (`ADMIN_TOKEN`)** — if `ADMIN_TOKEN` env var is set, all `/__admin/*` endpoints now require the token via `X-Admin-Token` header or `?token=` query param. Without a token set, the panel remains open (development convenience). STRONGLY recommended for any public deployment.
11
+
-**Admin password from env var (`ADMIN_PASSWORD`)** — removed hardcoded plain-text admin password from source code. Now reads from `ADMIN_PASSWORD` env var (default: `IsotopeAI@2025!`). Set this before deploying to a public server.
12
+
-**Admin email from env var (`ADMIN_EMAIL`)** — moved hardcoded `elixir.suyashprabhu@gmail.com` to `ADMIN_EMAIL` env var. In `/__admin/verify` output the email is redacted (e.g. `el***@su***.com`) to avoid leaking it in browser HTML.
13
+
-**Rate limiting on auth routes** — `/__auth/signup` and `/__auth/login` now enforce 10 requests/minute per IP. Returns `HTTP 429 + Retry-After: 60` when limit is exceeded.
14
+
15
+
### Fixed
16
+
-**Service worker missing bundle bypass** — `Auth-*.js` and `useInvites-*.js` were not in the SW network-only list. Both are patched server-side; if the SW cached the originals the patches were silently lost after the first page load. Now excluded from SW cache.
17
+
-**Body size limit on POST handlers** — `readReqBody()` had no size cap. Added 1 MB limit; oversized requests are rejected immediately to prevent memory exhaustion.
18
+
-**Startup backfill LIMIT raised 500 → 2000** — all four startup backfill queries (`users`, `user_points`, `user_stats_summary`, `user_profiles`) now fetch up to 2000 rows. Deployments with >500 users were silently missing backfills.
19
+
-**`package.json` version corrected** — was `1.1.3`, now `2.3.0` (matching CHANGELOG).
20
+
21
+
### Changed
22
+
-`.env.example` updated with `ADMIN_TOKEN`, `ADMIN_PASSWORD`, `ADMIN_EMAIL` documentation.
-**Service-role key in App bundle**: `getPatchedAppBundle()` injects the service_role key into the JS sent to all browsers. This is intentional for self-hosted/trusted-user deployments but documented clearly in AUDIT.md and AGENTS.md as a high-severity consideration for public deployments.
62
+
-**CORS wildcard on proxy**: `/__supa/*` proxy returns `Access-Control-Allow-Origin: *` — intentional for Replit preview iframe compatibility.
63
+
64
+
---
65
+
9
66
## Session: 2026-06-01 — RLS Fix, Community Events, Server Restart, GitHub Push
0 commit comments