Как проверить безопасность проекта из Lovable, Bolt или Cursor: чек-лист

27 сентября 2026 · 12 мин чтения · Безопасность, пункты 01–06, 12

Проект из 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-сервиса это главный пункт. Проверки по схеме базы не отличают правильную политику от политики с ошибкой в условии, поэтому нужен тест с двумя аккаунтами.

  1. Создайте две тестовые организации и по пользователю в каждой.
  2. Войдите пользователем A. В DevTools → Application → Local Storage найдите ключ вида sb-<PROJECT_REF>-auth-token и скопируйте из него access_token.
  3. Запросите данные организации 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, без оценки их условий. Насколько точна текущая глубокая проверка, мы не измеряли.

Что делать, если нашли проблему

Исправляйте в таком порядке:

  1. Перевыпустите утёкшие секретные ключи.
  2. Включите RLS и закройте открытые таблицы.
  3. Закройте функции и адреса API без проверки доступа.
  4. Обновите зависимости с уязвимостями уровня critical и high.
  5. Остальные пункты.

Если персональные данные пользователей могли попасть к посторонним, по ч. 3.1 ст. 21 152-ФЗ оператор должен уведомить Роскомнадзор в течение 24 часов, а о результатах внутреннего расследования — в течение 72 часов. Другие требования закона к таким проектам разобраны в статье Проект на Lovable и 152-ФЗ.

Если проект готовится к росту, стоит заодно проверить и производительность: почему вайбкод-проект тормозит при росте.

Статья не является юридической консультацией.

Если хотите, чтобы проект проверил инженер, оставьте заявку на Кодосмотр.