Přejít na obsah

Zabezpečení Lovable aplikace: 12 kontrol a 8 navíc

Aktualizováno

Zobrazit jako MarkdownOtevřít v ClaudeOtevřít v ChatGPTOtevřít v Perplexity

Otázka se zkopíruje také. Pokud se chat otevře prázdný, vložte ji.

TL;DR

Aplikace z Lovable je stejně bezpečná jako její databáze Supabase a „RLS je zapnuté“ dokazuje velmi málo. Testujte se dvěma uživateli ve dvou firmách, role držte mimo metadata uživatele, tajný klíč mimo prohlížeč a granty, views, storage, funkce a limity požadavků kontrolujte zvlášť, protože každé z nich obchází vaše politiky po svém. Níže je seznam, který procházím, prompt, který můžete vložit do Lovable nebo Claude, a osm kontrol, které jsem přidal poté, co mi aplikace klienta ukázala, co prvních dvanáct míjí.

Jsem Denys, full-stack a AI inženýr. Tento měsíc jsem opravoval klientovu aplikaci postavenou v Lovable. Všechno běželo na Supabase, jako obvykle, a bezpečnostních oprav bylo tolik, že se zdálo, jako by aplikace z nich byla složená. Tohle je seznam, který teď procházím u každého projektu v Lovable nebo na Supabase, než prohlásím data zákazníků za chráněná.

Je Lovable bezpečný? Dosavadní bezpečnostní problémy

Platforma aplikaci staví a hostuje, ale to, zda je aplikace bezpečná, závisí hlavně na databázi Supabase za ní, protože aplikace tuto databázi čte i zapisuje přímo z prohlížeče. Veřejné záznamy ukazují oba druhy problémů:

Kdy Co se stalo Zdroj
Březen 2025 CVE-2025-48757: sken 1 645 ukázkových aplikací z Lovable našel 303 endpointů ve 170 z nich, které vydávaly data komukoli s veřejným klíčem, protože RLS chybělo nebo bylo příliš volné Zveřejnění Matta Palmera, květen 2025
Únor 2026 Jedna aplikace hostovaná na Lovable odkryla 18 697 záznamů uživatelů; kontrola přístupu v jejích funkcích pouštěla dovnitř anonymní návštěvníky a blokovala přihlášené uživatele. Lovable uvedl, že část kódu nevygeneroval Lovable The Register, 27. února 2026
3. února – 20. dubna 2026 Regrese na platformě umožnila ostatním uživatelům Lovable číst historii chatu a zdrojový kód veřejných projektů Příspěvek Lovable o incidentu, 22. dubna 2026

První dva případy jsou díry na úrovni aplikace, přesně takové, jaké zachytí kontroly níže. Třetí byl chybou samotného Lovable a Lovable ji opravil; vaším dílem je držet klíče mimo chaty a kód (kontrola 3) a rotovat všechny, které tam byly. Lovable před publikací spouští bezpečnostní sken, ale jednat podle něj je na vás, a v době zveřejnění CVE tento sken kontroloval, že politika existuje, ne že je správná. Otázka „je Lovable bezpečný“ se tedy scvrkává na to, zda vaše databáze projde kontrolami níže.

Proč v aplikaci z Lovable nestačí „RLS je zapnuté“?

Aplikace z Lovable mluví s databází přímo z prohlížeče. Žádný váš vlastní backend mezi tím není: stránka volá Supabase Data API veřejným klíčem a o tom, co se vrátí, rozhoduje Postgres (která schémata toto API nabízí, to je samostatné nastavení, popsané v Supabase exposed schemas). Každé pravidlo, které chrání data zákazníků, proto musí žít v databázi, a databáze má několik dveří.

Row level security je jedny z nich. Granty rozhodují, zda se role vůbec smí dotknout tabulky, politiky rozhodují o tom, které řádky, a tři věci politiky přeskočí úplně: tajný klíč, views vytvořené bez security_invoker a funkce SECURITY DEFINER. Není to teorie. Vlastní bezpečnostní průvodce Lovable vás žádá, abyste zkontrolovali RLS politiky, které nastavilo, a CVE-2025-48757 výše ukazuje, co se stane, když to nikdo nekontroluje.

Čtyři cesty požadavku k vašim datům. Jen první hlídají vaše politiky RLS. Běžný požadavek: Prohlížeč → Grant → Politika RLS → Vlastní řádky; Tajný klíč v edge funkci: Prohlížeč → Edge funkce → Tajný klíč → Každý řádek; View bez security_invoker: Prohlížeč → View → Práva vlastníka → Každý řádek; Funkce SECURITY DEFINER: Prohlížeč → RPC → Práva vlastníka → Každý řádek.
Obrázek 1. Jen první cestu kontrolují vaše politiky. Zbylé tři běží s právy, která RLS přeskakují. Zdroj: dokumentace Supabase k RLS a zabezpečení API, říjen 2026.

Prompt: vložte ho do Lovable nebo Claude

Můžete ho vložit tak, jak je. Výsledek si pak zkontrolujte sami: AI ráda řekne „hotovo“, i když to neplatí, a prompt, po kterém chyba zmizí, to může udělat rozšířením přístupu.

Zkontroluj tento projekt z hlediska bezpečnosti, oprav, co najdeš, a napiš mi, co jsi změnil:

1. Testuj se dvěma uživateli ve dvou firmách. Uživatel A zkusí číst, upravit a smazat záznamy uživatele B podle id, přes API, vyhledávání a exporty. Vše musí selhat.
2. RLS na každé tabulce, politiky kontrolují vlastníka řádku nebo firmu. „Přihlášený“ nestačí.
3. Klíč service role nikdy ve frontendu. Edge funkce, které ho používají, samy kontrolují uživatele a filtrují podle firmy, klíč RLS obchází.
4. Role, tarif a id firmy nikdy z metadat uživatele, uživatelé je mohou upravit. Drž je v tabulce, kterou zapisuje jen server.
5. Když požadavek posílá dvě id (projekt + úkol), zkontroluj, že úkol patří k tomu projektu.
6. Odeber anon a authenticated všechna oprávnění k tabulkám a vrať jen to, co politiky potřebují. RLS nezastaví TRUNCATE. Každá migrace, která vytváří tabulku, obsahuje její GRANT: od 30. října 2026 Supabase nové tabulky automaticky nezpřístupňuje a aplikace dostane chybu 42501.
7. Všechny views se security_invoker = true, jinak RLS přeskakují.
8. Storage buckety: uživatelé čtou a zapisují jen vlastní soubory, žádné veřejné buckety pro soukromá data.
9. Funkce SECURITY DEFINER: NULL musí znamenat zamítnutí, ne povolení.
10. Limity požadavků na přihlášení, registraci, reset hesla a OTP, uložené v DB, ne v paměti.
11. Validuj veškerý vstup na serveru.
12. Spusť Supabase security advisor a oprav každé varování.

12 kontrol a jak každou dokázat

1. Dva uživatelé ve dvou firmách

Vytvořte uživatele A ve firmě 1 a uživatele B ve firmě 2, každého s několika záznamy. Přihlaste se jako A a zkuste záznamy B číst, upravit a smazat podle id, přes API, přes vyhledávání a přes každý export. Každý pokus musí nevrátit nic, nebo skončit chybou. Je to jediný test, který zachytí většinu toho, co následuje, protože testuje, co dělá útočník, ne to, co jste napsali.

Dva uživatelé, dvě firmy. Uživatel A z firmy 1 zkouší záznamy firmy 2. Každá cesta musí vrátit nic. Podle id přes API: Uživatel A → Id záznamu B → Číst, upravit, smazat → 0 řádků nebo chyba; Přes vyhledávání: Uživatel A → Hledat text B → Výsledky → Žádné řádky B; Přes export: Uživatel A → Export → Soubor → Žádné řádky B.
Obrázek 2. Test dvou firem. Úspěch znamená, že každá cesta vrátí z firmy 2 nic.

Přidejte třetího uživatele, který patří do obou firem. Politika ve tvaru „volající je členem firmy řádku“ dovolí tomuto uživateli číst řádky firmy 2, zatímco pracuje ve firmě 1. V jiné aplikaci na Supabase vrátila moje sonda na takovém uživateli dokument druhé firmy, dokud dotaz nefiltroval i podle firmy požadavku. Popsal jsem to v poznámce uživatel ve dvou org, kterého RLS neizolovalo.

2. RLS na každé tabulce, omezené na vlastníka nebo firmu

auth.uid() is not null znamená „jakýkoli přihlášený uživatel“, což na veřejné registrační stránce znamená kohokoli. Každá politika porovnává vlastníka nebo firmu řádku s volajícím. Vypište tabulky, které mají RLS pořád vypnuté:

select c.relname
from pg_class c join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'public' and c.relkind in ('r', 'p') and not c.relrowsecurity;

3. Tajný klíč nikdy ve frontendu

Klíč service role a novější klíč sb_secret_ obcházejí každou politiku. Prohledejte sestavený JavaScript na oba a vyměňte každý klíč, který kdy byl nasazen. Edge funkce, které ho používají, musí samy ověřit, kdo uživatel je, a filtrovat podle firmy, protože s tímto klíčem to neudělá nic jiného.

4. Role, tarif a id firmy nikdy z metadat uživatele

raw_user_meta_data je cokoli, co klient poslal do signUp, a uživatelé to mohou později změnit. V jiné aplikaci četl trigger nového uživatele pozvanou roli odtud, takže kdokoli, kdo se zaregistroval, mohl předat roli vlastníka a stát se Ownerem. Role, tarify a id firem držte v tabulce, kterou zapisuje jen server, nebo v app_metadata. Celý příběh: role převzatá z metadat při registraci.

5. Dvě id v jednom požadavku: zkontrolujte, že k sobě patří

Když požadavek nese id projektu a id úkolu, autorizovat projekt nestačí. Uživatel s právy k projektu A pošle A plus id sekce z projektu B a řádek skončí v B. RLS to nezachytí, protože insert označí řádek útočníkovým vlastním id projektu, a to politika právě kontroluje. Před zápisem ověřte, že podřízený záznam patří k nadřazenému.

6. Granty: odeberte vše, vraťte jen potřebné

Granty a politiky jsou dvě oddělené vrstvy. Přidáním politik se grant nevezme zpět, a proto vám průvodce RLS od Supabase radí odebrat a explicitně vrátit. V jiném projektu dal image supabase/postgres 17.6.1 rolím anon a authenticated oprávnění TRUNCATE, REFERENCES, TRIGGER a MAINTAIN na každou tabulku v public a na TRUNCATE se žádná politika nevztahuje. Data API nemá endpoint pro TRUNCATE, takže to není smazání jedním požadavkem, ale žádná klientská role to nepotřebuje a každá funkce, která spouští SQL pod touto rolí, to zdědí.

revoke all on public.orders from anon, authenticated;
grant select, insert, update on public.orders to authenticated;

select grantee, table_name, privilege_type
from information_schema.role_table_grants
where table_schema = 'public' and grantee in ('anon', 'authenticated')
order by table_name;

Jedno datum tuto kontrolu mění. Supabase přestává nové tabulky automaticky zpřístupňovat: nové projekty od 30. května 2026 a všechny existující projekty od 30. října 2026, včetně těch, které vytvořilo Lovable. Poté je tabulka, kterou Lovable nebo migrace vytvoří bez explicitního GRANT, pro aplikaci neviditelná: požadavek selže s chybou 42501 a funkce, která tabulku používá, přestane fungovat. Každá migrace, která vytváří tabulku, proto nově nese i její granty, vedle enable row level security a politik.

Dvě věci zůstávají stejné. Existující tabulky si granty ponechají, takže odebrat, co nepotřebujete, je pořád vaše práce. A změna bere zpět jen select, insert, update a delete: v projektu z Lovable přicházely nové tabulky i s novými výchozími hodnotami pořád s TRUNCATE, REFERENCES, TRIGGER a MAINTAIN pro anon a authenticated. Nejdřív odebrat vše a pak udělit je pořád bezpečné pořadí.

7. Každé view se security_invoker = true

View běží s právy svého vlastníka a v Supabase je vlastníkem obvykle postgres, takže view nad chráněnou tabulkou vydá každý řádek, který politiky zadržují. Na Postgres 15 a novějším:

alter view public.customer_summary set (security_invoker = true);

8. Storage: jen vlastní soubory, žádný veřejný bucket pro soukromá data

Veřejný bucket vydá kterýkoli soubor komukoli, kdo zná URL. Soukromé soubory patří do soukromého bucketu s politikami na storage.objects, které kontrolují vlastníka nebo firmu, obvykle podle první složky cesty. Po přesunu projektu spočítejte živé politiky storage: v jedné aplikaci po přesunu selhal každý upload, protože migrace politik nikdy neproběhla a tabulka měla zapnuté RLS s nulou politik.

9. Funkce SECURITY DEFINER: NULL znamená zamítnutí

V PL/pgSQL if not (has_permission or assignee_id = auth.uid()) nevyhodí výjimku, když je assignee_id null: celá podmínka je null a if ji přeskočí. Stejný výraz je uvnitř politiky bezpečný, protože ta bere null jako zamítnutí. V jedné aplikaci to dovolilo roli se všemi oprávněními vypnutými jednat se všemi 3683 úkoly, protože žádný neměl řešitele. Obalte podmínku do coalesce(…, false). Podrobnosti: NULL v PL/pgSQL IF NOT přeskočil kontrolu u 3683 úkolů.

10. Limity požadavků uložené v databázi

Omezte přihlášení, registraci, reset hesla a OTP a počítadlo držte v Postgresu. V aplikaci z Lovable žily limity v proměnné uvnitř edge funkce. Hostovaný projekt jsem otestoval 17. října 2026: každý požadavek běžel v novém isolate, takže počítadlo v paměti bylo vždy 1 a limit se nikdy nemohl spustit. Lokální supabase functions serve isolate znovu používá, takže stejný kód prošel každým lokálním testem.

Kde žije počítadlo, určuje, zda zabere. Limit požadavků v hostované edge funkci Supabase. Počítadlo v paměti funkce: Požadavek → Nový isolate → Počítadlo = 1 → Nikdy omezeno; Počítadlo v Postgresu: Požadavek → claim_rate_limit → Sdílený řádek → 429 při limitu.
Obrázek 3. Moje sonda hostované edge funkce Supabase, 17. října 2026: každý požadavek spustil nový isolate.

Klíč záleží stejně jako úložiště. Na hostované platformě je poslední hop v X-Forwarded-For vlastní proxy Supabase, takže klíčování podle něj dá všechny volající do jednoho koše, a x-client-ip nastavuje klient. V mé sondě nesl skutečného klienta cf-connecting-ip. Oprava byla funkce SECURITY DEFINER claim_rate_limit(bucket, key, max, window), kterou smí spustit jen service role, serializovaná advisory zámkem, ukládající hash IP nebo id uživatele místo syrové hodnoty.

11. Validujte veškerý vstup na serveru

Ať formulář kontroluje cokoli, API přijme všechno, co klient pošle. Délky, formáty, enumy a vlastnictví se kontrolují v databázi (constraints, triggery) nebo v edge funkci, nikdy jen v Reactu.

12. Supabase Security Advisor, každé varování

Otevřete Advisors a pak Security Advisor a opravte každý nález. Označuje tabulky s vypnutým RLS, views, které RLS přeskakují, politiky čtoucí metadata uživatele, příliš povolné politiky using (true) a funkce s proměnlivým search_path. Kontroly 1, 5, 9 a 10 vidět nemůže, protože se týkají logiky, ne konfigurace.

Co mě aplikace z Lovable naučila, co těch 12 míjí?

Tohle vzešlo z klientovy aplikace a jejích revizí. Žádné z toho se neobjeví ve skeneru.

  1. Pole, která klient nesmí nastavovat. Klient si sám poslal status: 'approved', čímž přeskočil moderaci. UPDATE politika, jejíž with check je volnější než její using, také dovolí uživateli přesunout řádek k jinému vlastníkovi. Politika hodnotu spočítat neumí, a proto trigger BEFORE INSERT OR UPDATE znovu odvodí status, roli, cenu a firmu z vlastních dat serveru a ignoruje, co poslal klient.
  2. Každá cesta zápisu, ne jen hlavní insert. Poté co byl opraven hlavní insert, stejný průnik seděl v přílohách, komentářích, obnovení soft-deleted položky a počítadlech. Vypište všechny zapisovatele chráněného sloupce, než opravíte prvního.
  3. Allow-listy, ne deny-listy. Zfalšované záznamy daly pět kol revize, protože každá oprava zablokovala jednu kombinaci a sousední nechala otevřenou. Trigger, který povoluje jen vyjmenované kombinace typu a stavu, uzavřel celou třídu najednou.
  4. Funkce jsou také API. Každá funkce v public je volatelná přes /rpc jakoukoli rolí s EXECUTE a RLS se na funkce nevztahuje. Každé funkci SECURITY DEFINER dejte set search_path = '', odeberte EXECUTE od public, anon a authenticated a udělte ho jen roli, která ho potřebuje.
  5. Odebrání EXECUTE může rozbít veřejné stránky. Postgres kontroluje EXECUTE u každé funkce použité v každé politice, která se na roli vztahuje, i ve větvi, která by se nikdy nespustila. Jakmile anon ztratil EXECUTE na is_admin(), každé anonymní čtení skončilo chybou 42501. Politiky jen pro adminy patří to authenticated a veřejná čtení dostanou vlastní politiku bez admin větve.
  6. Registrace se zapnutým potvrzením e-mailu. Se zapnutým potvrzením signUp nevrací session, takže jakýkoli zápis profilu hned po něm běží jako anon a tiše nezapíše nic. Projekty v Lovable mají často zapnuté auto-confirm, což chybu skryje. Pole předejte v signUp({ options: { data } }), nechte je validovat a zapsat triggerem nového uživatele a ta metadata berte jako nedůvěryhodná (kontrola 4).
  7. Testy, které procházejí z nesprávného důvodu. Lokální stack a hostovaný projekt měly jiná výchozí oprávnění, takže „anon nemůže vkládat“ lokálně prošlo, protože chyběl grant, ne proto, že RLS fungovalo. Negativní test má smysl, jen když existuje pozitivní grant. Porovnejte pg_default_acl lokálně a v produkci.
  8. Živá databáze, ne soubory migrací. Po migraci nebo přesunu projektu porovnejte, co je opravdu živé: pg_policies, pg_get_functiondef u každé stráže a granty výše. V jiné aplikaci nová migrace zkopírovala tělo staré funkce a tiše vrátila pozdější opravu.

Je aplikace z Lovable v souladu s GDPR?

Lovable aplikaci do souladu s GDPR nedostane ani z něj nevyvede; rozhoduje to, co aplikace dělá s osobními údaji, a bezpečnostní revize na to neodpoví. Tohle je šest mezer, které v aplikaci na Lovable Cloud kontroluji, každá s opravou:

  1. Vypište všechny zpracovatele. Lovable Cloud provozuje databázi, autentizaci, úložiště a funkce na Supabase, Lovable hostuje web a může posílat přihlašovací e-maily a Lovable AI Gateway předává text poskytovateli modelu. Doplňte každou e-mailovou, AI nebo scrapingovou službu, kterou vaše funkce volají. Každá, která dostává osobní údaje, potřebuje smlouvu o zpracování osobních údajů (DPA), a ta mimo EU navíc mechanismus předávání. Region hostingu v kódu nikde není, takže se na něj zeptejte.
  2. Smažte uživatele, který má obsah. Cizí klíče z toho, co uživatel napsal, mohou smazání zablokovat, a pak žádost o výmaz nejde splnit. Nastavte těmto klíčům cascade nebo set null, přidejte trigger při smazání, který odstraní i e-mailové logy a přihlašovací tokeny uživatele, a držte databázový test, který takového uživatele smaže.
  3. Stanovte dobu uchování. E-mailové logy, sledování zobrazení, fronty neúspěšných e-mailů a soft-deleted řádky si osobní údaje často drží bez konce. Plánovaná úloha, která soft-deleted řádky po pevné době smaže natrvalo i s jejich soubory, uzavře většinu.
  4. Sledování e-mailů jen se souhlasem. Zaznamenávat otevření a kliknutí po jednotlivých příjemcích vyžaduje podle pravidel ePrivacy souhlas: příznak souhlasu, ve výchozím stavu vypnutý, s časovým razítkem od serveru, ne od klienta.
  5. Držte adresy mimo logy funkcí. Logy edge functions se nečistí, takže console.log s adresou příjemce ji tam nechá. Logujte ID a počty.
  6. Zapněte potvrzení e-mailu. S automatickým potvrzením se kdokoli může zaregistrovat s adresou, která mu nepatří, a dostat do aplikace adresu skutečného člověka. Bod 6 v seznamu výše řeší stranu registrace.

Jak zkontrolovat vlastní aplikaci: najděte ve funkcích API klíče a vypište služby, smažte testovacího uživatele s obsahem, hledejte @ v logech funkcí a vyžádejte si od každého poskytovatele smlouvu o zpracování. Nejde o právní radu.

Jak zařídit, aby se to nevrátilo?

Každá kontrola výše je dotaz nebo test, takže je držte v repozitáři a spouštějte před každým nasazením. Testy pgTAP od Supabase pokryjí granty, politiky a funkce; test dvou firem patří vedle nich. Pokud má vaše aplikace role a obrazovku oprávnění, nestačí ani test na každou politiku: každé políčko oprávnění dokazuji proti kopii produkce, popsáno v jak testovat Supabase RLS, kde 30 z 87 políček nedělalo nic. Bezplatná Kontrola zabezpečení Supabase spustí 46 pravidel OWASP Top 10:2025 nad rolemi, granty, politikami a nastavením autentizace projektu, proto ji použijte pro první průchod; test dvou firem a vše kolem vašeho rozhraní zůstává ruční.

Co tento seznam nepokrývá: platby a webhooky, tajemství v historii Gitu, bezpečnostní hlavičky na hostingu, zálohy. Jsou důležité, ale jsou to jiný checklist.

Pokud jste zdědili aplikaci z Lovable nebo na Supabase a nejste si jistí, kterými z těchto kontrol prochází, od tohoto auditu začíná záchrana projektu. Případová studie evidence času pro auditorskou firmu ukazuje, jak vypadají kontroly rolí v produkční aplikaci.

Našli jste díru, kterou tento seznam míjí?

Rád si ji poslechnu. Rád porovnám zkušenosti se zabezpečením aplikací v Lovable a na Supabase.

Ozvěte se

© 2026 Denys Zaichenko. Původní článek: https://madsalt.tech/cs/blog/lovable-app-security-checklist/