hallint: линтер, который ловит баги безопасности от AI-ассистентов

· 2 мин чтения
ai-coding security static-analysis open-source linting
hallint: линтер, который ловит баги безопасности от AI-ассистентов

AI-ассистенты вроде Copilot, Cursor и ChatGPT пишут код быстрее человека — но у них есть системная слепая зона: они воспроизводят одни и те же классы уязвимостей снова и снова, причём с абсолютной уверенностью. Традиционные линтеры вроде ESLint проектировались для человеческого кода и не ловят эти паттерны. Инструмент hallint создан именно для этого — это бесплатный open-source статический анализатор, заточенный под характерные ошибки AI-генерации.

Почему ESLint не справляется с AI-кодом

AI-ассистенты ошибаются не так, как люди. Когда вы просите LLM сгенерировать Express-роут или запрос к базе данных, модель идёт по пути наименьшего сопротивления. Код проходит поверхностное ревью, работает в локальном окружении — и создаёт критические уязвимости в продакшене. Вот типичные паттерны:

  1. Захардкоженные секреты — AI с готовностью выдаст const API_KEY = "sk-abc123...". ESLint пропускает, а пуш в публичный репозиторий превращает это в катастрофу.

  2. SQL-инъекции по умолчанию — AI обожает template literals: db.query(\SELECT * FROM users WHERE id = ${req.params.id}`)`. На вид безобидно, но это хрестоматийный вектор SQL-инъекции.

  3. Пропущенная аутентификация — сгенерировать CRUD-роуты легко, а вот применить auth middleware к каждому из них AI забывает постоянно.

  4. Маскировка ошибок аутентификации — особенно коварный паттерн. Когда AI просят добавить обработку ошибок в auth middleware, он часто генерирует try/catch, который перехватывает ошибку токена, но всё равно вызывает next(), молча пропуская неаутентифицированные запросы.

  5. Разрешительный CORScors({ origin: '*' }) — любимый однострочник AI для «исправления» ошибок CORS.

Что такое hallint

hallint — это TypeScript-библиотека и CLI-инструмент, который сканирует JavaScript-, TypeScript- и Python-кодовые базы на специфические для AI проблемы безопасности и качества. Вместо того чтобы быть универсальным линтером, он использует три слоя детекции:

  • Regex-паттерны — молниеносный первый проход по известным плохим шаблонам.
  • AST-анализ — структурные проверки, понимающие логику кода, а не только его текст.
  • LLM-ревью (опционально) — семантический анализ логических потоков через Anthropic, OpenAI или локальный Ollama.

Набор правил

На текущий момент hallint включает 11 целевых правил:

Правило Критичность Что обнаруживает
hardcoded-secret Critical API-ключи, токены, известные префиксы (ghp_, sk-)
sql-injection Critical Пользовательский ввод, напрямую интерполированный в SQL-запросы
unsafe-eval Critical eval() или new Function() с динамическим вводом
auth-masking Critical Блоки catch, которые проглатывают ошибки аутентификации, делая отказ невидимым
missing-auth-check High Обработчики роутов без middleware аутентификации
xss-innerHTML High Несанитизированные строки, присвоенные напрямую в .innerHTML
permissive-cors High cors({ origin: '*' }) в обработчиках роутов
jwt-in-localstorage High JWT или auth-токены, сохраняемые в localStorage
swallowed-error High Пустые или содержащие только комментарий блоки catch
http-not-https Medium Закодированные http:// URL в fetch/axios-запросах
async-no-catch Medium async-функции без какой-либо обработки ошибок

Использование

Запустить hallint можно без установки — через npx:

npx @asyncinnovator/hallint-cli ./src

Пример вывода:

hallint scanning ./src...

src/routes/users.ts
  users.ts:4  CRITICAL  [hardcoded-secret]
  Hardcoded secret detected
  > const apiKey = "sk-abc123def456ghi789jkl"
  fix: Move to environment variables: process.env.YOUR_SECRET_NAME

  users.ts:9  CRITICAL  [sql-injection]
  Possible SQL injection
  > const result = await db.query(`SELECT * FROM users WHERE name = ${req.query.name}`)
  fix: Use parameterized queries: db.query('SELECT * FROM users WHERE name = $1', [req.query.name])

Summary: 2 issue(s) in 1 file(s) — 12ms
  2 critical

Для интеграции в собственные пайплайны, pre-commit хуки или редакторные плагины можно подключить библиотеку напрямую:

npm install @asyncinnovator/hallint
import { scan, scanSource } from '@asyncinnovator/hallint'

const result = await scan({
  files: ['./src/**/*.ts'],
  rules: 'recommended',
  minSeverity: 'high',
})

const findings = scanSource(
  `const key = "sk-abc123abc123abc123abc"`,
  'virtual.ts'
)

Почему это важно

Главное преимущество hallint перед LLM-ревью — детерминизм. Правило «строка начинается с sk- и содержит 40 символов — отклонить» даёт гарантию, которую вероятностная модель обеспечить не может. Паттерн маскировки ошибок аутентификации особенно показателен: код с try/catch, который вызывает next() после перехвата ошибки токена, выглядит абсолютно корректно при беглом осмотре, но молча отключает проверку аутентификации. Эту ошибку практически всегда допускает именно AI — человек, пишущий auth-логику с нуля, так не ошибается.

Инструмент распространяется под лицензией MIT, разрабатывается сообществом и легко расширяется. Если вы встречали AI-специфичный паттерн уязвимости, который ещё не покрыт, pull requests приветствуются.

Ссылки:

Источник: https://dev.to/asyncinnovator/stop-letting-ai-write-security-bugs-introducing-hallint-2hh2