Twilio approval, an exposed database, and Rankee's site-wide audit
12 commits across 4 repos · 4 Labs docs · one live security exposure closed.
Shipped
| Repo | Commit | What |
|---|---|---|
| Rankee | c72c4e2 | Site-wide audit + Google Optimization — audits only ever read the homepage |
265299a | Retry transient DataForSEO failures instead of failing the whole batch | |
90c76b5 | Stop discarding keywords when the SERP fetch fails | |
1344edb | Pick a tracked keyword when running a Local Falcon scan | |
2eae64a | Tie Local Falcon scans to clients; locations sync button | |
9dc4074 | Show unrun migrations in Admin before they look like broken features | |
| bm-vercel | 70506d6 | SMS consent checkbox — the A2P 10DLC rejection fix |
922f09c | Stop crawlers hitting protected preview deployments (the GSC 401) | |
5cc88c0 | Replyee chat lead webhook receiver → SureContact | |
baf8d76 | Homepage headline widened beyond restaurants | |
| Replyee | d33211c | Per-bot Quick Questions chips in the chat widget |
| Bloggy | bbf3ab4 | Stop bot spam on the waitlist endpoint |
Found & fixed
Closed Twilio A2P 10DLC campaign approved
Rejected on error 30896 — the contact form had no SMS opt-in checkbox. Added a dedicated,
unchecked, optional checkbox with full disclosures plus proof-of-consent storage (verbatim
language, version, URL, timestamp, server-side IP and user agent). Approved the same
day; campaign CM9fc0398… is registered with the carriers.
Critical The shared database was readable by anyone
Supabase linter output turned out to be an active, exploitable exposure. The anon
key is public by design and Replyee's /api/bot-config hands it to every visitor of
every client site. Verified with that key: email_verifications (10 rows) and
loyalty_transactions (4 rows) were readable by anyone.
password_reset_tokens was equally unprotected — empty at that moment, but
world-readable the instant anyone requested a reset.
Closed via staged RLS SQL. Re-verified afterwards with the same key: zero rows.
BOO's menu API still returned 15 categories / 154 items, so ordering never broke. Storage buckets
fh-media, client-documents, cmd-lead-photos and
backups made private; 25 functions had search_path locked.
Rankee audits only ever read the homepage
boommedia.us scored 100/100 with zero issues because its homepage genuinely is clean — while 14 of its other 29 pages had truncated titles, 10 had over-long descriptions, one served no H1, and 31 pages were missing from the sitemap. Built a real site-wide crawler plus 16 site-level checks.
Keywords were being silently discarded
A transient DataForSEO 40101 meant the keyword was never registered for tracking at
all — you would have re-entered those nine forever with nothing indicating they had been lost.
Bloggy: removing a form does not remove the endpoint
The waitlist form was gone from the page but /api/waitlist was still live and
unprotected, so bots kept posting. It also interpolated user input unescaped into the notification
email. Added a honeypot, validation, escaping and a gibberish heuristic — verified against both
real spam samples and 17 legitimate business names.
Decided
- Time tracking: TimeCamp Free ($0, unlimited users, API) for billable hours; Premium (~$14/mo) for new hires only. Rize has no public API, which rules it out. Clockify's free auto-tracker is "visible only to you" — useless for oversight.
- Security monitoring: it is two products, not one. Availability is free and takes an afternoon; attack reporting is Compliee's, already spec'd. The unified dashboard belongs in bm-portal, built last, as an aggregator that owns no data.
- Team-clock vs client-billable was a false choice — build billable, and the clock falls out as an aggregate.
- bm-portal: one request object, two views. The client's board and the all-client board are the same rows filtered differently.
Open
- Needs you Storage query 1b output — anonymous bucket enumeration is still possible; the policy list is needed before dropping anything.
- Needs you Rankee locations sync —
rk_locationsexists but is empty; click Sync locations in Admin. - Needs you TimeCamp: confirm whether mixed tiers are allowed. That single answer is ~$168/yr versus Premium for everyone.
- Risk
rankee.onlineapex returns 503 behind an untrusted certificate;wwwis fine. - Risk Backups have never been restore-tested. A backup you have never restored is a hypothesis.
- Queued UptimeRobot Phase 0 — free, ~30 min, closes the alerting gap behind two outages.
- Queued bm-portal requests table + kanban, once the mockup is approved.
Corrections made to my own work
- Said Rankee was on Coolify needing manual deploys — wrong, it is on Vercel and auto-deploys.
- Reported 4 orphan pages in the SEO audit — actually 31; I had read static routes only and missed
services/[slug]. - Called
fh-mediaan active resident-data breach — it is empty; unprotected but unpopulated. - Put DataForSEO
40102and40200in the retry set — one is a real answer, the other an empty balance. - Said the Bloggy folder was broken — it is not; it tracks
masterwhile production deploys from an unrelatedmain. - Corrupted a file with a NUL byte from my own heredoc; caught and fixed before commit.
Docs added to Labs
- boommedia.us SEO audit — live crawl of all 30 pages
- Replyee vs Zoho SalesIQ — 13 built, 2 partial, 15 missing
- Time tracking & employee monitoring — verified pricing, ROI calculator, 4-phase checklist
- Security & status monitoring centre — $0 recurring, Boom Media as client zero
- bm-portal dashboards — admin + client mockups for approval
Housekeeping
.md/ reorganised into ecosystem/ boo/ infrastructure/ integrations/ builds/;
new SaaS/README.md maps the workspace. A drift check across all 17 repos confirmed
nothing is unpushed — and surfaced that Bloggy has two unrelated histories on GitHub,
with the local folder tracking the branch that is not deployed.