# Michael Bires — Vibe-Code Rescue & Emergency Web Repair > Senior full-stack engineer. I audit, fix, harden, and deploy broken AI-built apps and hacked WordPress sites. Fixed prices, audit-first. I am a senior full-stack engineer specializing in rescuing AI-generated (vibe-coded) apps and cleaning up hacked WordPress sites. I diagnose before I touch a line of code, work at fixed prices, and harden every project so it doesn't break again. ## Services - [Vibe-Code Rescue](https://michaelbir.es/services/vibe-code-rescue): Your AI-built app works in the demo but breaks in production. - Triage / Audit ($299 — 48 hours): Know exactly what's wrong before spending more. - Priority Fixes ($799 — 3–5 days): The audit plus the fixes that unblock you. - Hardening & Deploy ($1,799 — 1–2 weeks): From fragile prototype to production-ready. - [Web Ambulance](https://michaelbir.es/services/hacked-wordpress-cleanup): Site hacked or down? Get a senior engineer on it now. - Emergency Cleanup ($349 — typically < 24 hours): Full cleanup with the root cause actually closed. - Care Plan (from $79/mo): So this never happens again. ## Fix-it guides - [Works in the Demo, Breaks in Production: The 6 Vibe-Code Failures](https://michaelbir.es/fix/ai-app-breaks-in-production): The six most common reasons AI-built apps (Lovable, Bolt, v0, Replit, Cursor) fail in production — and how to triage them without going in circles. - [How to Deploy a Lovable App to Production (Without It Breaking)](https://michaelbir.es/fix/deploy-lovable-app-production): A production deployment checklist for Lovable apps: custom domains, environment variables, Supabase configuration, and the failures that only appear after going live. - [Lovable App Broke After an Update? How to Recover Without Burning Credits](https://michaelbir.es/fix/lovable-app-broke-after-update): Your Lovable app worked yesterday. After a platform update, a deploy, or a 'security fix' prompt, everything broke. Here's how to triage regressions and when to stop prompting. - [Lovable Emails Not Sending? Fix Signup & Password Reset](https://michaelbir.es/fix/lovable-email-not-sending): Users sign up but never get a confirmation email? Password reset links go nowhere? Supabase's built-in email is rate-limited and lands in spam — here's how to fix it. - [Lovable Google Login Not Working? Fix the localhost Redirect](https://michaelbir.es/fix/lovable-google-login-not-working): Sign in with Google works on localhost but redirects to localhost:3000 on your Lovable preview or custom domain? It's almost always Supabase URL configuration — here's the fix. - [Stripe Webhooks Not Firing After Deploy? Here's How to Fix It](https://michaelbir.es/fix/stripe-webhook-not-firing): Payments succeed but orders never complete? The 5 reasons Stripe webhooks stop firing after you deploy — and how to fix each one. - [Supabase RLS Not Working (or Disabled)? Fix It Before Someone Finds It](https://michaelbir.es/fix/supabase-rls-not-working): Why ~70% of Lovable apps ship with row-level security disabled, what CVE-2025-48757 means for your app, and how to enable RLS without breaking everything. - [Why Google Can't See Your Vibe-Coded Site (And How to Fix It)](https://michaelbir.es/fix/vibe-coded-site-not-indexed-google): AI-built sites are client-side rendered — Google may index an empty shell and AI crawlers see nothing at all. Here's how to check and how SSR fixes it. ## Case studies - [Compromised WooCommerce Store Cleaned & Hardened in Under 24 Hours](https://michaelbir.es/case-studies/woocommerce-hack-cleanup): Three backdoors removed after a scanner plugin failed twice, entry point closed, and the store back online clean — all in under 24 hours. - [CVE-2025-48757: 170+ Lovable Apps With Open Supabase Tables](https://michaelbir.es/case-studies/lovable-supabase-rls-security-audit): Matt Palmer's coordinated disclosure found 303 exposed endpoints across 170 Lovable projects — including Linkable, a Lovable marketing site. What happened, what leaked, and how I fix the same pattern for founders. - [Documented: Stripe Bypass on Linkable (CVE-2025-48757 Follow-Up)](https://michaelbir.es/case-studies/lovable-stripe-webhooks-saas): Matt Palmer's May 2025 re-test of Linkable showed payments could be marked 'paid' via a direct Supabase POST — bypassing Stripe. The same RLS class of bug breaks legitimate webhook flows in Lovable SaaS apps. - [Documented: Lovable Google Login Redirects to localhost:3000](https://michaelbir.es/case-studies/lovable-google-login-custom-domain): A published Medium walkthrough by Ishwar Rimal (Intuit) describes the exact failure: Google OAuth works locally but redirects to localhost on Lovable preview URLs. Industry triage data puts this at ~15% of broken Lovable deploys. - [Documented: Non-Technical PM Stuck in AI Debug Loops for 3 Months](https://michaelbir.es/case-studies/lovable-production-rescue-after-ai-loop): Andreea Papillon's published 3-part series describes building with AI without dev resources: 90% backend bugs, auth taking 3–5× longer, and Claude/Cursor going in circles for days. The rescue pattern I sell exists because of stories like this. ## Contact - [Contact form](https://michaelbir.es/contact): describe the problem, get a reply within 24 hours - Email: hello@michaelbir.es - LinkedIn: https://www.linkedin.com/in/michael-bires/ ## Optional - [llms-full.txt](https://michaelbir.es/llms-full.txt): full text of every guide and case study in one file --- # Works in the Demo, Breaks in Production: The 6 Vibe-Code Failures URL: https://michaelbir.es/fix/ai-app-breaks-in-production Published: 2026-07-06 Every rescued vibe-coded app I've seen failed for a variation of the same six problems. If your AI-built app works in the preview but falls apart with real users, triage it in this order. ## 1. Authentication that only worked in the sandbox Sessions drop, password resets 404, OAuth loops back to the login page. Usually: redirect URLs still pointing at the dev/preview domain, cookies misconfigured for the production domain, or the AI mixed two auth patterns that fight each other. Google sign-in redirecting to `localhost:3000` is the most common variant ([full fix](/fix/lovable-google-login-not-working/)); missing confirmation emails are usually SMTP, not frontend code ([email guide](/fix/lovable-email-not-sending/)). **Triage:** open the browser dev-tools Network tab during login. The first failing redirect or 401 tells you which layer is lying. ## 2. Database security that doesn't exist The app "works" because every table is publicly readable and writable — row-level security is off. This is the silent one: nothing looks broken until your data leaks. Roughly 70% of Lovable apps ship this way ([how to check and fix](/fix/supabase-rls-not-working/)). **Triage:** Supabase Table Editor → look for "RLS disabled" badges. This one is urgent even though nothing "looks" broken. ## 3. Payments that succeed without fulfilling Stripe takes the money; your app never finds out. Webhook endpoint on the wrong URL, wrong signing secret, or a parsed request body breaking signature verification ([the five causes](/fix/stripe-webhook-not-firing/)). **Triage:** Stripe Dashboard → Webhooks → recent deliveries. The response codes tell the story. ## 4. Environment & CORS chaos Works locally because `.env` had everything; production has half of it. Symptoms: blank pages, "undefined is not a function" in the console, API calls blocked by CORS, or — worse — secret keys shipped into the frontend bundle because the AI didn't know the difference. **Triage:** compare local `.env` against the hosting provider's environment variables line by line, then check the browser console for CORS errors and grep the built JS for `sk_live` / `service_role`. ## 5. Deploys that fail or half-succeed Build passes but the page is blank; custom domain shows an old version; every deploy needs a manual ritual someone has to remember. There's no CI/CD, no rollback, no monitoring — the AI built an app, not an operation. **Triage:** can you answer "what exactly runs in production right now, and how do we get back to the previous version?" If not, this is your problem even when nothing is currently on fire. ## 6. The AI is going in circles The meta-failure: every prompt fixes one symptom and creates two more. This happens because the codebase has accumulated contradictory patterns — three ways of fetching data, two auth flows, dead code the AI keeps "fixing." Past a certain entropy point, prompting is negative progress. If the app broke after a Lovable update or a half-finished "security fix," start with the regression triage ([post-update guide](/fix/lovable-app-broke-after-update/)). **Triage:** if the last ten prompts haven't produced net progress, stop prompting. The codebase needs a human root-cause read, and possibly a scoped rebuild of the rotten parts. ## The honest way out These six failures compound — broken env vars cause webhook failures cause "fixes" that break auth. Fixing them one symptom at a time is how you got here. I do it the other way around: a fixed-price **$299 triage** reads the entire codebase, finds the root causes, and gives you a video walkthrough + written report with an honest rescue-vs-rebuild recommendation — in 48 hours, before you spend anything on fixes. --- # How to Deploy a Lovable App to Production (Without It Breaking) URL: https://michaelbir.es/fix/deploy-lovable-app-production Published: 2026-07-06 Lovable's **Publish** button gets you a live URL. It does not get you a production app. The gap between the two is where most Lovable projects die — and where paying customers hit errors your demo never showed. Here's the checklist I run when taking a Lovable app to real production. ## 1. Domain and URLs - Connect your custom domain (Project → Settings → Domains) and wait for DNS + SSL to go green. - Then update **every place that stored the old URL**: Supabase Auth → URL Configuration (Site URL + redirect URLs), OAuth providers (Google/GitHub callback URLs), and Stripe webhook endpoints. Auth "works on the lovable.app URL but not on my domain" is almost always a stale redirect URL ([Google login fix](/fix/lovable-google-login-not-working/)). ## 2. Environment variables and secrets Lovable manages Supabase keys for you, but anything else — Stripe keys, email API keys, third-party tokens — must be checked: - **No secrets in frontend code.** Anything in the React code ships to every visitor. Search for `sk_live`, `service_role`, and API keys. - Secret keys belong in **Supabase Edge Function secrets** (or your backend host's env vars), never in the client. - Test keys (`sk_test_...`) must be swapped for live keys — in the server environment, not the code. ## 3. Supabase production configuration This is the big one. Before real users arrive: - **Row-level security on every table, with policies.** ~70% of Lovable apps ship with RLS disabled ([full guide here](/fix/supabase-rls-not-working/)) — that's your entire database public. - **Auth settings:** disable auto-confirm if you don't want fake signups; configure a real SMTP provider (the built-in email service is rate-limited and lands in spam — [email setup guide](/fix/lovable-email-not-sending/)). - **Backups:** confirm point-in-time recovery or at minimum daily backups are enabled on your Supabase plan. ## 4. Payments - Stripe webhook endpoint pointing at the production domain, with the production signing secret ([common failures here](/fix/stripe-webhook-not-firing/)). - Run one real live-mode transaction end to end: pay, webhook received, order recorded, email sent, refund works. ## 5. The things nobody thinks about until they hurt - **Error visibility:** by default you'll never know production is broken until a customer emails you. Add error tracking (e.g. Sentry) — Lovable apps ship with none. - **SEO / indexability:** Lovable apps are client-side rendered; Google may see an empty page ([why, and the fix](/fix/vibe-coded-site-not-indexed-google/)). - **Rate limiting & abuse:** public forms and endpoints will be found by bots within days. - **A rollback plan:** know how to get back to the last working version before you need to. ## When the deploy itself keeps failing Build errors after connecting GitHub, blank white pages on the custom domain, infinite loading — these usually trace back to environment differences, not the code the AI wrote last. The fastest path is a root-cause diagnosis rather than another 50 prompts. That's my Hardening & Deploy package: environments, CI/CD, monitoring, OWASP + RLS hardening, and your app live on your domain — $1,799 fixed. Or start with the $299 triage to find out exactly what stands between your demo and production. --- # Lovable App Broke After an Update? How to Recover Without Burning Credits URL: https://michaelbir.es/fix/lovable-app-broke-after-update Published: 2026-07-06 It worked yesterday. Today the preview is blank, login fails, or a feature you shipped last week vanished. You didn't change much — maybe Lovable updated something, you connected GitHub, you asked for a "security fix," or you ran out of credits mid-change. You're not alone. **Post-update regressions** are one of the fastest-growing support themes for vibe-coded apps in 2026. ## The four usual causes ### 1. A half-finished AI change You asked for a fix. The AI edited six files, hit a credit limit, or you reverted one file manually. The codebase is now **inconsistent** — two auth patterns, old env vars, dead imports. Symptoms: build passes but page is blank; or one feature works and another 404s. **Triage:** Project → History in Lovable. Find the last version that worked. Note the timestamp. Don't prompt forward from a broken state — restore or compare. ### 2. Platform or dependency shift Lovable, Supabase, or a npm dependency updated. Something that compiled yesterday fails today. Common signs: new TypeScript errors in the build log, Supabase client API mismatch, or Edge Function runtime change. **Triage:** Read the **build error verbatim** — the first error line, not the last. That's usually the root cause; the rest is cascade. ### 3. "Security fix" that broke the app A common pattern: you ask to secure the database. The AI enables RLS with no policies, moves API keys around, or changes auth — the app shows empty data or won't log in. G2 reviews of Lovable explicitly mention security prompts that **alter layout and consume credits** without fixing the real issue. **Triage:** Supabase → Table Editor. If RLS just got enabled and lists are empty, that's your answer ([RLS guide](/fix/supabase-rls-not-working/)). ### 4. Environment / URL drift You added a custom domain, switched from preview to production, or cloned to GitHub. Redirect URLs, Stripe webhooks, and env vars still point at the old URL. The app "broke" when you went live — not because the code regressed, but because **the environment changed**. **Triage:** [Production deploy checklist](/fix/deploy-lovable-app-production/) — domain, Supabase URLs, Stripe, env vars line by line. ## What to do in the first hour (don't prompt yet) 1. **Write down what worked and when** — last known good date, last feature that worked, last URL that worked. 2. **Check Lovable build/deploy logs** — failed build vs successful deploy with broken runtime are different problems. 3. **Open browser DevTools → Console** on the broken page — screenshot the first red error. 4. **Check Supabase Auth logs and Stripe webhook deliveries** if login or payments broke. 5. **Stop after 3 failed prompts** — if each fix creates new errors, you're in a negative-progress loop. ## The credit-burn trap Every "try this" prompt costs credits. Regression debugging is the worst credit burn: you're undoing damage, not building features. Founders report burning a month's allowance in a single afternoon toggling between two broken states. **Better move:** freeze the codebase, document symptoms, get a human root-cause read. That's exactly what the $299 triage is for — full audit in 48 hours, video walkthrough, honest "restore vs fix vs rebuild" recommendation, credited toward fixes. ## Symptom → likely fix map | What broke | Check first | |------------|-------------| | Blank white page | Console errors; failed JS bundle; env vars missing in production | | Login stopped working | Supabase Site URL / redirect URLs ([Google login guide](/fix/lovable-google-login-not-working/)) | | Data disappeared | RLS enabled without policies | | Payments stopped | Stripe webhook URL still on preview domain ([webhook guide](/fix/stripe-webhook-not-firing/)) | | Emails stopped | SMTP / rate limits ([email guide](/fix/lovable-email-not-sending/)) | | Everything at once | Half-finished AI change — restore last good version, then audit | ## When the app can't be saved Sometimes the fastest recovery is: restore last known good from Lovable history or GitHub, redeploy, then **harden one layer at a time** with a human driving. If history is messy or GitHub sync diverged, the triage tells you whether rescue ($799) or a scoped rebuild is cheaper than another week of prompts. Tell me what broke, when, and what you already tried — [start with triage](/services/vibe-code-rescue) before you spend more credits. --- # Lovable Emails Not Sending? Fix Signup & Password Reset URL: https://michaelbir.es/fix/lovable-email-not-sending Published: 2026-07-06 Your auth flow "works" — until a real user signs up and never receives a confirmation email. Or they click "Forgot password" and nothing arrives. You check spam. Nothing. You ask Lovable to fix it. It changes the email template. Still nothing. This isn't a frontend bug. **Supabase sends the emails**, and the default setup is fine for demos, not for production. ## Why emails fail in Lovable apps 1. **Built-in Supabase email** — rate-limited (a handful per hour), shared infrastructure, aggressive spam filtering. Fine for testing; unreliable for customers. 2. **Site URL / redirect URLs wrong** — password reset links point at `localhost` or an old preview URL ([same fix as Google login](/fix/lovable-google-login-not-working/)). 3. **Auto-confirm enabled** — you never notice missing emails because test accounts skip verification; real users hit flows you never tested. 4. **No custom SMTP** — production apps need a real email provider (Resend, Postmark, SendGrid, AWS SES). ## Quick checks (2 minutes) 1. **Supabase Dashboard → Authentication → Users** — did the user actually get created? If yes, the app works; email delivery is the problem. 2. **Authentication → Logs** — look for email send failures or rate-limit errors. 3. **Authentication → URL Configuration** — Site URL must match your live domain. Reset links use this. 4. Try signup with your own email. Wait 5 minutes. Check spam **and** promotions tab. ## The real fix: custom SMTP ### Option A — Resend (most common for Lovable stacks) 1. Create a [Resend](https://resend.com) account and verify your domain (DNS records: SPF, DKIM). 2. Supabase Dashboard → **Project Settings → Authentication → SMTP Settings**. 3. Enable custom SMTP: | Field | Typical value | |-------|----------------| | Host | `smtp.resend.com` | | Port | `465` (SSL) | | Username | `resend` | | Password | Your Resend API key | | Sender email | `noreply@yourdomain.com` (must be on verified domain) | 4. **Authentication → Email Templates** — customize confirm signup and reset password templates. Ensure links use `{{ .ConfirmationURL }}` and `{{ .SiteURL }}` correctly. ### Option B — Other providers Postmark, SendGrid, and AWS SES work the same way: verify domain, add SMTP credentials in Supabase, set a real sender address on your domain. ## Auth settings to verify while you're there - **Enable email confirmations** if you want verified users — and test the full flow after enabling. - **Secure email change** — on for production. - **Password reset** — confirm redirect URL in the template matches your live Site URL. - **Rate limits** — Supabase Auth rate limits can block bursts of signups; check **Authentication → Rate Limits** if emails stop after a spike. ## "Emails worked yesterday" If nothing changed in your code but email stopped: - You hit the **built-in email quota** (resets slowly). - Your domain got **greylisted** because you sent from an unverified address. - Supabase **Site URL changed** when you connected a custom domain — reset links now point somewhere invalid. ## When to bring me in Email + auth + custom domain issues often stack: wrong Site URL, no SMTP, and a broken reset flow in the app. Fixing one in isolation wastes another week of prompts. My $299 triage maps every auth and email path (signup, confirm, reset, magic link), checks Supabase and your live domain, and gives you a fix plan — or I wire SMTP, templates, and redirects in the Priority Fixes package ($799). --- # Lovable Google Login Not Working? Fix the localhost Redirect URL: https://michaelbir.es/fix/lovable-google-login-not-working Published: 2026-07-06 You added "Sign in with Google." It works when you test locally. On your Lovable preview URL or custom domain, clicking the button sends you to `localhost:3000` — or loops forever, or lands on a blank page. This is the **#1 auth problem** I see in Lovable + Supabase apps. It's not your Google settings alone. Supabase is the middleman, and it's still pointing at the wrong place. ## Why this happens The OAuth flow goes: your app → Google → **Supabase** → back to your app. Supabase decides the final redirect using **Site URL** and **Redirect URLs** in the Auth settings. Lovable and local dev often leave these at `http://localhost:3000`. Google OAuth can succeed and Supabase still sends users to localhost. ## Fix it in 10 minutes ### 1. Supabase → Authentication → URL Configuration Update **Site URL** to your live URL — not localhost: - Lovable preview: `https://preview-xxxxx.lovable.app` (or your `.lovable.dev` preview) - Custom domain: `https://yourdomain.com` - Production: whichever URL users actually open in the browser Under **Redirect URLs**, add every URL users might land on after login: ``` https://preview-xxxxx.lovable.app/** https://yourdomain.com/** https://*.lovable.app/** ``` The `/**` wildcard matters — Supabase rejects redirects that aren't explicitly allowed. ### 2. Google Cloud Console → OAuth client Under **Authorized redirect URIs**, you need Supabase's callback — not your app URL: ``` https://YOUR-PROJECT-REF.supabase.co/auth/v1/callback ``` Under **Authorized JavaScript origins**, add your app domains: ``` https://preview-xxxxx.lovable.app https://yourdomain.com ``` Do **not** put `localhost` here for production testing unless you're still developing locally. ### 3. Lovable custom domain? Update everything again Connecting a custom domain is a common trigger: auth "worked on the lovable.app URL" and breaks on your domain. Every time the public URL changes, repeat step 1 for the new domain. Also update Stripe webhooks and any OAuth provider if you added more than Google ([production deploy checklist](/fix/deploy-lovable-app-production/)). ### 4. Test in an incognito window Cached sessions hide redirect bugs. Open a private window, go to your **production or preview URL** (not localhost), and try Google sign-in once. ## Still broken? Check these | Symptom | Likely cause | |---------|----------------| | Redirects to localhost | Site URL still `localhost:3000` in Supabase | | "redirect_uri_mismatch" | Google callback URI missing or wrong project ref | | Infinite redirect loop | Site URL and Redirect URLs disagree; or http vs https mismatch | | Login works but user is logged out on refresh | Cookie domain / session storage mismatch across subdomains | | Works on preview, fails on custom domain | Custom domain not added to Supabase Redirect URLs | Open browser DevTools → **Network** tab during login. The first failed redirect (302 to wrong host, or 400 from Supabase) tells you which layer is wrong. ## When to stop prompting the AI If you've updated Supabase and Google three times and it still redirects to localhost, the codebase may have a hardcoded `redirectTo: 'http://localhost:3000'` in the sign-in call. The AI will often "fix" OAuth by changing the wrong file and burning credits. That's a $299 triage job: I trace the actual `signInWithOAuth` call, align every URL across Supabase, Google, and your deployed domain, and verify login holds in production — usually same day. --- # Stripe Webhooks Not Firing After Deploy? Here's How to Fix It URL: https://michaelbir.es/fix/stripe-webhook-not-firing Published: 2026-07-06 Your checkout works. Stripe shows the payment as succeeded. But the order never completes — no confirmation email, no subscription activated, no database record. Locally, everything worked. This is the single most common failure I see in AI-built (Lovable, Bolt, v0, Cursor) apps that just went live. The good news: it's almost always one of five causes. ## 1. The webhook endpoint points at the wrong URL Stripe doesn't know you deployed. If you created the webhook endpoint during development, it's probably still pointing at a `localhost` tunnel or a preview URL. **Fix:** In the [Stripe Dashboard → Developers → Webhooks](https://dashboard.stripe.com/webhooks), check the endpoint URL. It must be your production domain, e.g. `https://yourapp.com/api/stripe/webhook` — not `localhost`, not an `*.vercel.app` preview URL that changes on every deploy. ## 2. You're using the wrong webhook signing secret Each webhook endpoint has its own signing secret (`whsec_...`). The secret from your local Stripe CLI (`stripe listen`) is **different** from the one for your production endpoint. If your deployed app still has the CLI secret, every event fails signature verification with a `400`. **Fix:** Copy the signing secret from the production endpoint in the Stripe Dashboard and set it as `STRIPE_WEBHOOK_SECRET` in your hosting provider's environment variables (e.g. Vercel → Project → Settings → Environment Variables). Then **redeploy** — env var changes don't apply to already-built deployments. ## 3. Test mode vs. live mode mismatch Test-mode webhooks only receive test-mode events, and live-mode webhooks only receive live-mode events. AI-generated code frequently ships with the test key (`sk_test_...`) in production. **Fix:** Make sure all three match the same mode: your secret key (`sk_live_...`), your publishable key, and the webhook endpoint (created while the dashboard was in live mode). ## 4. The request body is being parsed before verification Stripe signs the **raw** request body. If your framework parses the body into JSON before the signature check, verification fails every time. This bites Next.js, Express (`express.json()`), and most AI-generated handlers. **Fix (Next.js App Router):** read the raw text, then verify: ```ts export async function POST(req: Request) { const body = await req.text(); // raw body — do NOT use req.json() const sig = req.headers.get("stripe-signature")!; const event = stripe.webhooks.constructEvent( body, sig, process.env.STRIPE_WEBHOOK_SECRET! ); // handle event… return new Response(null, { status: 200 }); } ``` ## 5. The handler returns an error, so Stripe retries — then gives up If your handler throws (missing env var, database not reachable from production, RLS blocking the insert), Stripe records failed deliveries and eventually disables the endpoint. **Fix:** Open the endpoint in the Stripe Dashboard and look at the **recent deliveries** log — it shows the exact HTTP status and response body your server returned. That error message is usually the real root cause (often a Supabase insert failing because row-level security is enabled but no policy allows the service role — see my [Supabase RLS guide](/fix/supabase-rls-not-working/)). ## Still stuck? Webhook failures are rarely just webhook failures — they're usually a symptom of environment variables, database policies, or deploy configuration being broken at the same time. That's exactly what my fixed-price triage finds: a full audit of your app with a video walkthrough and prioritized fix list, in 48 hours, for $299. --- # Supabase RLS Not Working (or Disabled)? Fix It Before Someone Finds It URL: https://michaelbir.es/fix/supabase-rls-not-working Published: 2026-07-06 If your app was built with Lovable, Bolt, or another AI builder on top of Supabase, there's a very good chance your database is readable — possibly writable — by anyone on the internet right now. This isn't scaremongering. Research behind **CVE-2025-48757** (CVSS 8.26, High) found that roughly **70% of sampled Lovable-built apps had row-level security disabled entirely**, with 303 exposed endpoints confirmed across 170 projects — leaking everything from emails to payment data. The AI builds a working demo; it does not secure your tables. ## How to check if you're exposed (2 minutes) 1. Open your Supabase Dashboard → **Table Editor**. Any table with an "RLS disabled" warning badge is publicly accessible through your project's auto-generated REST API. 2. Confirm it from the outside — this is exactly what attackers do: ```bash curl "https://YOUR-PROJECT.supabase.co/rest/v1/users?select=*" \ -H "apikey: YOUR_ANON_KEY" ``` Your anon key is **not a secret** — it ships in your frontend JavaScript to every visitor. If that curl returns rows, so can anyone. ## Why "just enabling RLS" breaks your app Enabling RLS with no policies denies **everything** — and suddenly your app shows empty lists and silent failures. This is why the AI (or a previous developer) probably turned it off in the first place: the app "worked" without it. RLS needs to be enabled *and* given correct policies: ```sql -- Enable RLS on the table alter table public.orders enable row level security; -- Users can only see their own orders create policy "Users read own orders" on public.orders for select using (auth.uid() = user_id); -- Users can only insert orders for themselves create policy "Users insert own orders" on public.orders for insert with check (auth.uid() = user_id); ``` Every table needs this thinking applied: who may read which rows, who may write which rows, and what your server-side code (using the service role) does on behalf of users. ## The other landmine: the service role key The `service_role` key **bypasses RLS entirely**. It must only ever live in server-side environment variables. AI-generated code regularly embeds it in frontend code or commits it to the repo — at that point, RLS doesn't matter, the attacker has god mode. Search your codebase for `service_role` and rotate the key immediately if it appears anywhere a browser can see. ## The safe migration path 1. **Inventory** every table and what the frontend actually queries. 2. **Write policies first**, enable RLS table by table, testing each app flow as you go. 3. **Move privileged operations** (webhooks, admin actions) to server-side code using the service role — never the client. 4. **Verify from outside** with curl against the REST API using only the anon key. 5. **Rotate keys** if the service role key was ever exposed. ## When to bring me in If your app is live with real user data and RLS off, you have both a security emergency and a delicate migration — enabling policies wrong takes your app down. My $299 triage audits every table, policy, and key exposure in 48 hours and gives you a prioritized fix plan; the Priority Fixes package implements it without breaking your production app. --- # Why Google Can't See Your Vibe-Coded Site (And How to Fix It) URL: https://michaelbir.es/fix/vibe-coded-site-not-indexed-google Published: 2026-07-06 You launched, shared the link, and… you're invisible. Weeks later, Googling your own product name finds nothing. Your site isn't penalized — it's most likely **empty as far as crawlers are concerned**. ## Why this happens to AI-built sites Lovable, Bolt, v0-style builds are typically **client-side rendered (CSR)** React apps: the server sends a nearly empty HTML file plus a JavaScript bundle, and the browser builds the page. Humans never notice. Crawlers do: - **Google** *can* execute JavaScript, but rendering is deferred, budgeted, and unreliable — CSR sites index slower, partially, or with missing content and meta tags. - **AI crawlers (GPTBot, ClaudeBot, PerplexityBot) don't execute JavaScript at all.** As more buying research happens inside AI assistants, a CSR site simply doesn't exist to them. - **Social previews** (Open Graph) are read by scrapers that also don't run JS — that's why your links show no title or image on X/LinkedIn/Slack. ## Check what crawlers actually see (2 minutes) ```bash curl -s https://yoursite.com | grep -i "