BRANCH HQ · HEALTH CHECK

bookly-sample

Checked 19 October 2026 · Prepared by Branch HQ
7 serious problems need attention before this product takes on more users or data.
7Serious
2Should fix
0Minor

What was checked

Code scanned for security problems4 files · React, Express, Supabase, TypeScript
Secret keys in the project's historyNone found
Dependencies with known vulnerabilitiesNot checked
The project's own testsNone found
Live siteNot checked

Findings

Serious1. Database queries built from user input (SQL injection)

Text a visitor types is pasted straight into a database command, which can let them read or delete data they should not reach.

What to do: Pass every value as a query parameter instead of joining it into the SQL text.

server/index.ts:9
server/index.ts:9
const rows = await db.query(`SELECT * FROM bookings WHERE customer_name = '${name}'`)
Serious2. A secret is written into the code

A password, token or API key sits in the source code. Anyone who can see the code -- a past freelancer, a leaked copy -- can use it.

What to do: Move it to an environment variable, then revoke the old key where it was issued and create a new one.

src/components/Admin.tsx:3
src/components/Admin.tsx:3
const ADMIN_PASSWORD = 'book…'
Serious3. Anyone can run any command on the database

The app has a database function that runs whatever SQL it is given, and the website calls it with the public key every visitor has. Anyone can use it to read, change or delete all data.

What to do: Remove the function from the database now. Replace each use with a specific, limited function or a normal query that row-level security protects.

src/components/Admin.tsx:10 supabase/migrations/20260101000000_init.sql:15
src/components/Admin.tsx:10
return supabase.rpc('exec_sql', { sql })
supabase/migrations/20260101000000_init.sql:15
create or replace function public.exec_sql(sql text) returns void language plpgsql security definer as $$ begin execute sql; end $$;
Serious4. Secret keys sent to every visitor's browser

Settings starting with VITE_, NEXT_PUBLIC_, REACT_APP_ or EXPO_PUBLIC_ are copied into the website itself, so anyone can read these keys in their browser and use them -- running up your bill or reaching your data.

What to do: Move the call that needs the key to a server function, keep the key there without the public prefix, and replace the exposed key.

src/components/Assistant.tsx:3 .env:3
src/components/Assistant.tsx:3
const openai = new OpenAI({ apiKey: import.meta.env.VITE_OPENAI_API_KEY, dangerouslyAllowBrowser: true })
.env:3
VITE_OPENAI_API_KEY=sk-p…
Serious5. The Supabase admin key is in the code

The service_role key bypasses every database rule. Anyone who sees it -- in the code, a leaked copy, or the browser -- can read and change all data.

What to do: Revoke it in Supabase now, keep the new one only on the server (an environment variable), and use the anon key in the app.

src/integrations/supabase/client.ts:5
src/integrations/supabase/client.ts:5
const SUPABASE_KEY = 'eyJ…
Serious6. Database tables anyone can read (no row-level security)

These Supabase tables are created without row-level security, so anyone with the public key -- which every visitor's browser has -- can read, and often change, every row. (Unless it was switched on later in the Supabase dashboard: worth checking there.)

What to do: Enable row-level security on each table and add policies that let people see only their own rows.

supabase/migrations/20260101000000_init.sql:1
supabase/migrations/20260101000000_init.sql:1
create table public.bookings (
Serious7. Environment files with secrets are committed

These files hold passwords or keys and are part of the repository, so every copy of the code carries them.

What to do: Remove them from git, add .env to .gitignore, and replace every key they contained.

.env
Should fix8. Any website can make logged-in requests to the server

The server accepts requests from any website together with the visitor's login cookies, so another site can act as your logged-in users.

What to do: List the exact websites allowed (your own domain), instead of "*" or true.

server/index.ts:5
server/index.ts:5
app.use(cors({ origin: true, credentials: true }))
Should fix9. No automated tests

Nothing checks automatically that the product still works after a change, so every change is a risk that is only found by users.

What to do: Add tests for the few flows that matter most (sign-up, checkout, booking) and run them before every release.

Not covered by this report

Automated checks find known kinds of problem; they are not a full manual security audit, and a clean result does not guarantee there are none. Generated by Branch HQ 1.0.41. Nothing in the project was changed by this check.