Как проверить безопасность проекта из Lovable, Bolt или Cursor: чек-лист
Проект из Lovable, Bolt или Cursor можно проверить самостоятельно примерно за час. Главные пункты: нет ли секретных ключей в собранном JavaScript, включён ли RLS на всех таблицах Supabase, работают ли сброс пароля и роли, проверяются ли данные и файлы на сервере, нет ли уязвимых зависимостей и не видит ли один клиент данные другого. Бесплатные проверки Lovable и Supabase закрывают часть списка, логику доступа приходится проверять руками. Все шаги ниже выполняйте только на своём проекте, лучше на тестовой копии с тестовыми данными.
Насколько часто в коде от нейросети бывают уязвимости
Veracode в GenAI Code Security Report 2025 проверил код более 100 языковых моделей на 80 задачах на Java, JavaScript, Python и C# (пресс-релиз). В 45% случаев код содержал уязвимости из OWASP Top 10, списка самых распространённых классов веб-уязвимостей. Для JavaScript доля провалов составила 43%. От межсайтового скриптинга (XSS) код не защищал в 86% подходящих задач. В отчёте 2026 года средняя доля безопасных решений осталась на уровне 56%, по XSS — 15%.
Отчёт измеряет код на заранее подобранных задачах. Из него не следует, что 45% приложений на Lovable или Bolt уязвимы.
Пример из практики описан в CVE-2025-48757. Исследователь Мэтт Палмер проверил 1645 проектов на Lovable и нашёл 303 уязвимых адреса API в 170 из них, это около 10% (разбор автора). Утечки возникали из-за отсутствующих или неверных политик RLS в Supabase. По описанию CVE, без входа в систему можно было читать и менять таблицы сгенерированных сайтов. Автор перечисляет имена, email, данные о платежах и подписках, ключи сторонних сервисов. Lovable оспаривает CVE: по позиции компании, за защиту данных приложения отвечает его владелец.
Что понадобится для проверки
- Код проекта на компьютере, например через синхронизацию с GitHub, если она настроена.
- Node.js и npm.
- Два тестовых аккаунта. Для B2B-сервиса — в двух разных организациях.
- Доступ к панели Supabase, если проект подключён к вашему собственному Supabase.
Как найти секретные ключи в сборке фронтенда
Всё, что попало в сборку фронтенда, скачивает браузер каждого посетителя. В проектах на Vite в код попадают все переменные с префиксом VITE_, и документация Vite предупреждает, что ключам API в них не место.
У Supabase ключи двух видов (документация):
- publishable (
sb_publishable_...) и старый anon можно держать в браузере. Запросы с ними подчиняются политикам RLS. - secret (
sb_secret_...) и старый service_role обходят все политики RLS. Им место только на сервере.
Старые ключи anon и service_role Supabase выводит из употребления до конца 2026 года. Запрос с секретным ключом нового формата Supabase отклоняет с ошибкой 401, если запрос похож на браузерный (проверка по заголовку User-Agent). Ключ из бандла всё равно можно скопировать и использовать вне браузера.
Соберите проект и поищите ключи в папке сборки:
npm run build
grep -rnoE "sb_secret_[A-Za-z0-9_-]+|service_role" dist/
Старые ключи Supabase имеют формат JWT, и слово service_role в них закодировано. Эта команда находит все JWT в сборке и показывает их содержимое:
grep -rhoE "eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+" dist/ | sort -u |
while read -r token; do
node -e 'console.log(Buffer.from(process.argv[1].split(".")[1], "base64url").toString())' "$token"
done
"role":"anon" в выводе допустим. "role":"service_role" означает, что ключ нужно перевыпустить сегодня же. Отдельно поищите по названиям других подключённых сервисов: платёжного шлюза, почтовой рассылки, API нейросетей.
Если собрать проект локально нельзя, откройте опубликованный сайт в Chrome, затем DevTools и поиск по всем загруженным файлам (Cmd+Option+F на macOS, Ctrl+Shift+F на Windows). Ищите sb_secret_ и eyJ.
Ключи могли остаться в истории git. Для этого есть gitleaks и TruffleHog:
brew install gitleaks trufflehog
gitleaks git -v .
gitleaks dir -v dist
trufflehog git file://. --results=verified,unknown
TruffleHog проверяет найденные ключи запросом к API сервиса, которому они принадлежат. Для своих ключей это полезно: вы узнаёте, какие из них ещё действуют.
Удалить ключ из кода недостаточно, он остаётся в истории git и в уже скачанных копиях сайта. Создайте новый ключ в Supabase (Settings → API Keys), замените его везде, затем удалите старый secret-ключ или отключите старые ключи. Lovable рекомендует хранить ключи сторонних сервисов в разделе Secrets и вызывать API через серверные функции (документация Lovable).
Как проверить RLS в Supabase за 10 минут
Row Level Security (RLS) определяет, какие строки таблицы видит и меняет каждый запрос. Таблицы схемы public доступны через API Supabase с публичным ключом. Если RLS выключен, а у публичной роли есть права на таблицу, её может прочитать любой, у кого есть адрес проекта. На проектах, созданных до 30 мая 2026 года, Supabase выдаёт такие права новым таблицам автоматически.
Откройте в панели Supabase раздел Advisors → Security Advisor (документация). Первые предупреждения, которые стоит закрыть: rls_disabled_in_public (таблица без RLS) и permissive_rls_policy (политика, которая разрешает всё). Список таблиц без RLS даёт запрос в SQL Editor:
select c.relname as table_name
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;
Если проект работает на Lovable Cloud, доступа к панели Supabase нет (объяснение Supabase). Тогда используйте раздел Security в самом Lovable.
Подробный разбор с запросами к pg_policies, проверкой через curl и примерами правильных политик — в статье RLS в Supabase: как проверить, что таблицы не открыты всем.
Как проверить вход, сброс пароля, сессии и роли
- Сброс пароля. Запросите сброс для тестового аккаунта. Ссылка в письме должна вести на ваш домен, а повторный переход по ней не должен срабатывать. В Supabase откройте Authentication → URL Configuration: Site URL по умолчанию равен
http://localhost:3000, замените его на рабочий домен. Для Redirect URLs Supabase рекомендует в продакшене точные адреса, шаблон**оставьте для разработки. - Регистрация. Включите подтверждение email, это пункт чек-листа Supabase перед запуском. Пароли короче 8 символов Supabase не рекомендует. Проверка паролей по базе утечек HaveIBeenPwned есть на тарифе Pro и выше (документация).
- Сессии. Выйдите из аккаунта и откройте закрытую страницу по прямой ссылке. Данные не должны загрузиться.
- Админка. Войдите обычным пользователем и откройте
/adminпо прямой ссылке. Затем повторите запросы админки с токеном обычного пользователя. Скрытая кнопка в интерфейсе запросы не защищает, доступ должны ограничивать RLS или сервер. - Роли. Не храните роль в
user_metadata: пользователь может изменить эти данные сам (документация Supabase). Роль храните вapp_metadataили в отдельной таблице. Если роль лежит колонкой в таблице профилей, проверьте, может ли пользователь обновить её в своей строке.
Найти проверки ролей на стороне браузера поможет поиск по коду:
grep -rnE "isAdmin|user_metadata|role ?===" src/
Как проверить валидацию данных и загрузку файлов
Проверки в форме на сайте обходятся прямым запросом к API. Ограничения должны быть в базе или в серверной функции. Простейший вариант: ограничение на уровне таблицы.
alter table public.leads
add constraint leads_email_length check (char_length(email) <= 320);
XSS чаще всего появляется там, где пользовательский текст вставляется в страницу как HTML. Найдите такие места:
grep -rnE "dangerouslySetInnerHTML|innerHTML|v-html" src/
Каждое совпадение с данными от пользователя нужно либо убрать, либо пропустить через санитайзер, например DOMPurify.
Для загрузки файлов в Supabase Storage проверьте:
- Документы пользователей лежат в приватном бакете. Файлы публичного бакета доступны любому, у кого есть ссылка (документация).
- У бакета заданы ограничения
fileSizeLimitиallowedMimeTypes(документация). - Пользователь загружает файлы только в свою папку. Пример политики из документации Supabase:
create policy "Allow authenticated uploads"
on storage.objects
for insert
to authenticated
with check (
bucket_id = 'my_bucket_id' and
(storage.foldername(name))[1] = (select auth.jwt()->>'sub')
);
Как найти уязвимые зависимости: npm audit и OSV-Scanner
npm audit --omit=dev
npm audit fix
--omit=dev оставляет в отчёте только пакеты, которые попадают в рабочую сборку. Команду npm audit fix --force без разбора не запускайте: она ставит версии с несовместимыми изменениями, и документация npm прямо предупреждает об этом.
Для перекрёстной проверки подойдёт OSV-Scanner от Google. Он сверяет зависимости с открытой базой уязвимостей OSV:
brew install osv-scanner
osv-scanner scan -r .
Начинайте с уязвимостей уровня critical и high в пакетах, которые работают в продакшене.
Как проверить CORS, админки и отладочные адреса
CORS — правило браузера, которое определяет, каким чужим сайтам можно читать ответы вашего API. Опасная настройка: сервер повторяет любой присланный Origin и добавляет Access-Control-Allow-Credentials: true. Тогда чужой сайт может делать запросы с cookies вашего пользователя. По MDN для запросов с cookies * запрещён, нужен явный домен. Проверьте свой API:
curl -s -o /dev/null -D - -H "Origin: https://example.com" "https://api.ваш-домен.ru/api/me"
Если в ответе есть Access-Control-Allow-Origin: https://example.com вместе с Access-Control-Allow-Credentials: true, задайте список разрешённых доменов. Пример CORS для Edge Functions в документации Supabase использует *. Для функций, которые получают токен в заголовке Authorization и не используют cookies, это обычная настройка.
Что ещё проверить:
- Edge Functions без проверки токена. По умолчанию Supabase проверяет JWT до запуска функции (документация). Найдите исключения командой
grep -n "verify_jwt" supabase/config.toml. Каждая функция сverify_jwt = falseдолжна проверять вызывающего сама, например по подписи вебхука. - Отладочные и тестовые адреса. Поищите в коде маршруты вроде
/debug,/test,/seed:grep -rniE "debug|seed|/admin" src supabase/functions. - Карты исходников. Команда
find dist -name "*.map"показывает файлы, по которым исходный код читается целиком. Решите, нужны ли они на рабочем сайте. - Служебные файлы на своём сервере. Если сайт работает на вашем VPS,
curl -I https://ваш-домен.ru/.envиcurl -I https://ваш-домен.ru/.git/configдолжны возвращать 404.
Как проверить, что клиент A не видит данные клиента B
Для B2B-сервиса это главный пункт. Проверки по схеме базы не отличают правильную политику от политики с ошибкой в условии, поэтому нужен тест с двумя аккаунтами.
- Создайте две тестовые организации и по пользователю в каждой.
- Войдите пользователем A. В DevTools → Application → Local Storage найдите ключ вида
sb-<PROJECT_REF>-auth-tokenи скопируйте из негоaccess_token. - Запросите данные организации B с токеном пользователя A:
curl "https://<PROJECT_REF>.supabase.co/rest/v1/projects?select=*&org_id=eq.<ID_ОРГАНИЗАЦИИ_B>" \
-H "apikey: <PUBLISHABLE_KEY>" \
-H "Authorization: Bearer <ТОКЕН_ПОЛЬЗОВАТЕЛЯ_A>"
Правильный ответ: пустой массив []. Повторите для каждой таблицы с данными клиентов, для создания и изменения записей с чужим org_id и для файлов в Storage.
Отдельно проверьте серверные функции, которые работают с secret-ключом. Такой запрос обходит RLS, если в нём нет токена пользователя (документация), поэтому принадлежность к организации функция должна проверять в коде. Пример политики для B2B есть в статье про RLS.
Какие бесплатные инструменты помогут
| Инструмент | Что проверяет | Ограничения |
|---|---|---|
| Lovable, быстрая проверка | Правила доступа к базе, пробелы RLS, настройки паролей, уязвимые npm-пакеты, MCP-серверы без аутентификации. Запускается при каждой публикации | Фиксированный набор проверок |
| Lovable, глубокая проверка | Код приложения: права доступа, открытые эндпоинты, инъекции, утёкшие секреты, платежи, аутентификация, персональные данные | Запускается вручную |
| Supabase Security Advisor | RLS, представления, функции security definer, публичные бакеты, анонимный вход |
Видит схему базы, код приложения не видит. Недоступен на Lovable Cloud |
| gitleaks, TruffleHog | Секреты в коде и истории git | Публичные по замыслу ключи тоже попадают в отчёт |
| npm audit, OSV-Scanner | Известные уязвимости в зависимостях | Ошибки в вашем коде не находят |
Запуск проверок в Lovable бесплатный, исправления через чат расходуют кредиты. В документации Lovable сказано, что эти инструменты не гарантируют полной безопасности. В 2025 году автор CVE-2025-48757 писал, что тогдашний сканер Lovable проверял только наличие политик RLS, без оценки их условий. Насколько точна текущая глубокая проверка, мы не измеряли.
Что делать, если нашли проблему
Исправляйте в таком порядке:
- Перевыпустите утёкшие секретные ключи.
- Включите RLS и закройте открытые таблицы.
- Закройте функции и адреса API без проверки доступа.
- Обновите зависимости с уязвимостями уровня critical и high.
- Остальные пункты.
Если персональные данные пользователей могли попасть к посторонним, по ч. 3.1 ст. 21 152-ФЗ оператор должен уведомить Роскомнадзор в течение 24 часов, а о результатах внутреннего расследования — в течение 72 часов. Другие требования закона к таким проектам разобраны в статье Проект на Lovable и 152-ФЗ.
Если проект готовится к росту, стоит заодно проверить и производительность: почему вайбкод-проект тормозит при росте.
Статья не является юридической консультацией.
Если хотите, чтобы проект проверил инженер, оставьте заявку на Кодосмотр.