API ВЕГА

Valca

ИИ-помощник по безопасности кода — блокирует небезопасный код в момент его создания.

Ранее пакет публиковался под названием vigilsec. Теперь он называется valca. Команды valca и vigil работают, поэтому существующие хуки и скрипты продолжат запускаться без изменений.

Valca перехватывает каждый файл, созданный ИИ-помощником по программированию, и блокирует его, если обнаружены критические уязвимости уровня CRITICAL или HIGH, — ещё до записи файла на диск. Это единственный инструмент, который проверяет код в момент генерации, а не после коммита.

AI writes file → valca scan → exit 2 → Claude Code blocks the write

Проблема

ИИ-помощники по программированию воспроизводят самые распространённые шаблоны из обучающих данных. А самые распространённые шаблоны часто содержат небезопасные настройки по умолчанию.

Самый наглядный пример: все существующие сканеры IaC (Checkov, Trivy, Snyk, Semgrep) не обнаруживают привязку порта в docker-compose, которая открывает вашу базу данных для доступа из интернета:

ports:
  - "5432:5432"   # ← binds to 0.0.0.0, bypasses UFW, reachable from anywhere

Правильный вариант — "127.0.0.1:5432:5432". Valca обнаруживает эту проблему. Остальные инструменты — нет.


Установка

pip install valca

Настройте хук Claude Code (один раз):

valca init --global     # `valca init --global` also works

Готово. Теперь каждый файл, который создаёт Claude Code, проверяется до сохранения. Перезапустите Claude Code, чтобы активировать хук.


Доступ к сети

Основное сканирование Valca полностью выполняется офлайн: у пакета нет зависимостей времени выполнения, а движок никогда не отправляет ваш код, пути к файлам и результаты проверок куда-либо.

Три правила обращаются к сети, поскольку проверить, уязвима ли зависимость или существует ли она вообще, в офлайн-режиме невозможно. При сканировании манифеста (requirements.txt, package.json, lockfiles) эти правила отправляют только названия пакетов и строки версий на следующие адреса:

ХостИспользуется правиломПередаваемые данные
api.osv.devVGL-PKG001 (известная CVE для зафиксированной версии)название пакета + версия
pypi.orgVGL-PKG002/003/004 (несуществующий, устаревший или подозрительный пакет)название пакета
registry.npmjs.orgVGL-PKG002/003/004название пакета

Исходный код, содержимое файлов, пути к файлам и результаты сканирования никогда не передаются. Если даже список используемых зависимостей представляет для вас чувствительную информацию, отключите эти правила в .valcarc. Тогда Valca будет полностью работать офлайн:

disabled_rules = ["VGL-PKG001", "VGL-PKG002", "VGL-PKG003", "VGL-PKG004"]

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

results.sarif

Only report HIGH and above

valca scan ./my-project/ --severity HIGH

Open feedback & waitlist form

valca feedback">

# Scan a single file
valca scan docker-compose.yml

# Scan a directory
valca scan ./my-project/

# JSON output (for CI / dashboards)
valca scan ./my-project/ --format json

# SARIF output (for GitHub Advanced Security)
valca scan ./my-project/ --format sarif > results.sarif

# Only report HIGH and above
valca scan ./my-project/ --severity HIGH

# Open feedback & waitlist form
valca feedback

Просматривайте, что обнаружил сканер за всё время. Обе команды используют локальную историю проверок — данные не покидают ваш компьютер.

# Findings log — what was caught, where, and when
valca log                              # 20 most recent findings
valca log --severity CRITICAL          # only criticals
valca log --project api --since 2026-09-01
valca log --limit 100 --format json    # for dashboards

# Aggregate stats — rule frequency, severity mix, precision per rule
valca stats
valca stats --format json

Команда valca stats показывает, как часто срабатывает каждое правило и как часто вы его подавляли. Благодаря этому можно увидеть, какие правила дают низкую точность именно в вашей кодовой базе, вместо того чтобы строить предположения.

Коды завершения:

КодЗначение
0Уязвимости не обнаружены — запись продолжается
1Обнаружены только замечания (MEDIUM / LOW / INFO)
2Обнаружена уязвимость уровня CRITICAL или HIGH — Claude Code блокирует запись

Пример работы

Блокировка уязвимого workflow GitHub Actions в момент записи:

В апреле 2026 года исследователи обнаружили, что все три основных ИИ-помощника по программированию (Claude Code, Gemini CLI, Copilot) можно было взломать, чтобы похитить ANTHROPIC_API_KEY и GITHUB_TOKEN с помощью скрытого HTML-комментария в issue на GitHub. CVSS 9.4. Специальный доступ не требовался.

Valca обнаруживает уязвимый workflow (триггер issues: + ИИ-агент + API-ключ в env) до того, как он попадёт в git. Это единственный инструмент, который это делает.

→ Полный разбор: атака, которая крадёт ваши API-ключи через комментарий к issue на GitHub


Правила

116 правил в 27 категориях. Все встроены, используют только стандартную библиотеку и не имеют зависимостей времени выполнения.

Этот каталог формируется на основе реестра правил, поэтому он всегда соответствует правилам, включённым в движок.

Секреты и раскрытие учётных данных (14 правил)

ПравилоУровень серьёзностиЧто обнаруживает
VGL-I001CRITICALeval() или exec() — риск внедрения кода
VGL-I002HIGHsubprocess с shell=True
VGL-I003HIGHвызов os.system()
VGL-S001CRITICALжёстко заданный ключ доступа AWS
VGL-S002CRITICALжёстко заданный пароль
VGL-S003CRITICALжёстко заданный API-ключ
VGL-S004CRITICALжёстко заданный bearer-токен
VGL-S005CRITICALжёстко заданный секрет JWT
VGL-S006CRITICALзакрытый ключ PEM в исходном коде
VGL-S007CRITICALURL базы данных со встроенными учётными данными
VGL-S008CRITICALсекретный ключ Stripe для рабочей среды
VGL-S009CRITICALжёстко заданный токен Slack
VGL-S010CRITICALжёстко заданный API-ключ провайдера (OpenAI / GitHub / GitLab / Google)
VGL-S012HIGHнебезопасное значение-заглушка для критически важной конфигурации безопасности

GitHub Actions — поверхность атак на ИИ-агентов (13 правил)

ПравилоУровень серьёзностиЧто обнаруживает
VGL-GHA001CRITICALPwn Request — pull_request_target с ref для checkout, контролируемым злоумышленником
VGL-GHA002CRITICALвнедрение скрипта — выражение контекста, контролируемое пользователем, в шаге run:
VGL-GHA004HIGHсекрет напрямую подставляется в шаг run: и становится виден в таблице процессов
VGL-GHA005MEDIUMв workflow отсутствует явный блок permissions (неявная область разрешений GITHUB_TOKEN)
VGL-GHA006HIGHиспользование кэша в workflow pull_request (вектор атаки с отравлением кэша)
VGL-GHA007HIGHself-hosted runner с триггером pull_request (риск сохранения доступа к runner)
VGL-GHA008HIGHтриггер workflow_run без проверки ref и репозитория
VGL-GHA009CRITICALИИ-агент подключён к триггеру с недоверенными данными (issues/pull_request_target), API-ключ передаётся через env
VGL-GHA010HIGHИИ-агент запускается по pull_request_target без проверки, что запрос пришёл из fork
VGL-GHA011CRITICALнедоверенные данные события GitHub подставляются в prompt ИИ-агента
VGL-GHA012HIGHИИ-агент запускается по триггеру с недоверенными данными без ограничения --allowedTools
VGL-GHA013MEDIUMИИ-агент запускается по триггеру с недоверенными данными без ограничения --max-turns
VGL-GHA014HIGHразрешение contents: write предоставлено ИИ-агенту, работающему по триггеру с недоверенными данными

ИИ-агенты — внедрение prompt (9 правил)

ПравилоУровень серьёзностиЧто обнаруживает
VGL-PI001CRITICALпользовательский ввод подставляется в системный prompt LLM
VGL-PI002HIGHисходное тело HTTP-запроса используется как содержимое сообщения LLM
VGL-PI003HIGHдля формирования prompt используются строки с пользовательскими данными
VGL-PI004MEDIUMрезультат работы инструмента добавляется в диалог без очистки
VGL-PI005CRITICALданные HTTP-запроса попадают в prompt LLM без очистки
VGL-PI006CRITICALответ LLM передаётся в subprocess, exec или eval
VGL-PI007HIGHданные webhook напрямую передаются ИИ-агенту
VGL-PI008HIGHсодержимое базы данных подставляется в prompt — внедрение второго порядка
VGL-PI009HIGHпользовательский ввод записывается в векторное хранилище — отравление памяти

Усиление защиты Dockerfile (8 правил)

ПравилоУровень серьёзностиЧто обнаруживает
VGL-DF001HIGHDockerfile запускается от root — директива USER отсутствует
VGL-DF002MEDIUMв Dockerfile используется незакреплённый базовый образ :latest
VGL-DF003HIGHсекрет включён в слой ENV или ARG Dockerfile
VGL-DF004HIGHcurl
VGL-DF005HIGHв команде загрузки Dockerfile RUN отключена проверка TLS
VGL-DF006MEDIUMдля локальных файлов используется ADD — следует применять COPY
VGL-DF007HIGHиспользуется COPY . без .dockerignore — возможна утечка .git, .env и учётных данных
VGL-DF008MEDIUMв Dockerfile установлены права на запись для всех пользователей (chmod 777)

Docker Compose (7 правил)

ПравилоУровень критичностиЧто обнаруживает
VGL-D001CRITICALПубличная привязка порта Docker: обходит UFW и открывает сервис для доступа из интернета
VGL-D002HIGHВ блоке environment файла docker-compose указан секрет в открытом виде
VGL-D003CRITICALКонтейнер Docker запущен в привилегированном режиме
VGL-D004HIGHКонтейнер Docker использует сетевой режим хоста
VGL-D005CRITICALСокет Docker подключён к контейнеру — это позволяет полностью выйти за его пределы
VGL-D006HIGHК контейнеру подключён путь хоста, содержащий конфиденциальные данные
VGL-D007HIGHК контейнеру подключена директория с учётными данными AWS (~/.aws), что открывает доступ ко всем профилям

Terraform (7 правил)

ПравилоУровень критичностиЧто обнаруживает
VGL-TF001CRITICALСекретное значение жёстко задано в Terraform
VGL-TF002HIGHДля ресурса Terraform включён публичный доступ
VGL-TF003HIGHШифрование явно отключено в Terraform
VGL-TF004CRITICALНа инстансе EC2 включён IMDSv1 — уязвимость позволяет похищать метаданные через SSRF
VGL-TF005HIGHФайл состояния S3 backend для Terraform хранится без шифрования
VGL-TF006MEDIUMДля управляемого ресурса отключена защита от удаления
VGL-TF007MEDIUMДля управляемого через Terraform ресурса отключено журналирование аудита

Десериализация и обход путей (5 правил)

ПравилоУровень критичностиЧто обнаруживает
VGL-DESER001CRITICALНебезопасная десериализация: pickle.loads / pickle.load
VGL-DESER002HIGHНебезопасная десериализация YAML: yaml.load() без SafeLoader
VGL-DESER003HIGHНебезопасная десериализация: marshal.loads получает недоверенные данные
VGL-PATH001HIGHОбход путей: пользовательский ввод передаётся в file open или path join без проверки
VGL-SSTI001CRITICALВнедрение шаблона на стороне сервера: пользовательский ввод обрабатывается как шаблон Jinja2

Безопасность MCP Server (5 правил)

ПравилоУровень критичностиЧто обнаруживает
VGL-MCP001CRITICALВ описание инструмента MCP встроена prompt injection
VGL-MCP002HIGHОписание инструмента MCP формируется на основе данных, контролируемых пользователем
VGL-MCP003HIGHОбработчик инструмента MCP выполняет команды оболочки без изолированной среды
VGL-MCP004HIGHВ конфигурации MCP server используется пакет без фиксированной версии или конечная точка с обычным HTTP
VGL-MCP005HIGHИнструмент MCP для получения данных принимает URL, контролируемый агентом, без списка разрешённых адресов

Безопасность веб-приложений (5 правил)

ПравилоУровень критичностиЧто обнаруживает
VGL-CORS001HIGHПодстановочный символ в CORS: allow_origins=['*']
VGL-SQL001CRITICALSQL-инъекция: запрос формируется с помощью f-строки или конкатенации строк
VGL-SQL002CRITICALSQL-инъекция: в ORM используется raw query с f-строкой
VGL-SSL001HIGHПроверка SSL отключена
VGL-SSRF001CRITICALSSRF: HTTP-запрос выполняется по URL, контролируемому пользователем

AI Agent — чрезмерная автономность (4 правила)

ПравилоУровень критичностиЧто обнаруживает
VGL-A001CRITICALВывод LLM передаётся на выполнение в оболочку
VGL-A002HIGHЖёстко заданное автоматическое подтверждение отключает участие человека в процессе
VGL-A003HIGHЦикл агента не ограничен и не имеет лимита итераций
VGL-A004HIGHОтвет LLM записывается на диск без проверки

Аутентификация и сессии (4 правила)

ПравилоУровень критичностиЧто обнаруживает
VGL-AUTH001CRITICALВ JWT указан algorithm=none — проверка подписи обходится
VGL-AUTH002CRITICALВ JWT отключён verify_signature — принимаются любые токены
VGL-AUTH003HIGHСлабый или жёстко заданный секретный ключ веб-фреймворка
VGL-AUTH004HIGHВ коде фреймворка включён режим отладки

Целостность зависимостей (4 правила)

ПравилоУровень критичностиЧто обнаруживает
VGL-PKG001CRITICALАудит пакетов: CVE, галлюцинации, устаревшие версии и риски цепочки поставок
VGL-PKG002CRITICALПакет не найден в реестре: возможно, это галлюцинация или цель slopsquatting
VGL-PKG003HIGHВерсия пакета значительно отстаёт от последней — возможны устаревшие данные обучения AI
VGL-PKG004HIGHПакет недавно добавлен в реестр и имеет мало выпусков — риск для цепочки поставок

Kubernetes (4 правила)

ПравилоУровень критичностиЧто обнаруживает
VGL-K001CRITICALПривилегированный контейнер или доступ к пространству имён хоста
VGL-K002CRITICALВ securityContext Kubernetes включён allowPrivilegeEscalation
VGL-K003HIGHВ securityContext Kubernetes добавлены опасные возможности Linux
VGL-K004HIGHВ манифесте Kubernetes указан том hostPath с конфиденциальными данными

Журналирование и раскрытие данных (4 правила)

ПравилоУровень критичностиЧто обнаруживает
VGL-LOG001HIGHКонфиденциальные данные записываются в журналы (CWE-532)
VGL-LOG002HIGHПодробности ошибки раскрываются в теле HTTP-ответа (CWE-209)
VGL-LOG003MEDIUMИсключение незаметно игнорируется в контексте аутентификации или безопасности
VGL-LOG004MEDIUMРиск CRLF-инъекции: пользовательский ввод записывается в журнал без очистки символов перевода строки

Swift / iOS (4 правила)

ПравилоУровень критичностиЧто обнаруживает
VGL-SW001CRITICALСекрет жёстко задан в строковом литерале Swift
VGL-SW002HIGHВ сетевом коде Swift используется URL с обычным HTTP
VGL-SW003HIGHКонфиденциальное значение записывается в UserDefaults без шифрования
VGL-SW004CRITICALВ делегате URLSession обходится проверка сертификата SSL

Сканеры CVE зависимостей (3 правила)

ПравилоУровень критичностиЧто обнаруживает
VGL-DEP001HIGHУязвимые пакеты Python (pip-audit)
VGL-DEP002HIGHКритическая уязвимость npm (npm audit)
VGL-DEP003HIGHУязвимый пакет в lockfile (osv-scanner)

GitHub Actions — рекомендации по настройке workflow (3 правила)

ПравилоУровень критичностиЧто обнаруживает
VGL-GH001HIGHСекрет GitHub Actions выводится в шаге run и попадает в журнал
VGL-GH002HIGHWorkflow GitHub Actions запрашивает избыточные разрешения
VGL-GH003HIGHВ GitHub Actions используется изменяемая ссылка на действие (тег или ветка)

AI Agent — файлы конфигурации (2 правила)

ПравилоУровень критичностиЧто обнаруживает
VGL-AGENT001CRITICALВ файле конфигурации AI Agent содержатся инструкции по выполнению команд оболочки или извлечению данных
VGL-AGENT002HIGHУчётные данные раскрываются через обработчик исключений в коде агента

JavaScript / TypeScript (2 правила)

ПравилоУровень критичностиЧто обнаруживает
VGL-JS001HIGHДля секрета из process.env задана жёстко прописанная строка в качестве резервного значения
VGL-JS004HIGHeval() или new Function() вызывается с динамическим аргументом (CWE-95)

Безопасность на уровне строк (2 правила)

ПравилоУровень критичностиЧто обнаруживает
VGL-RLS001CRITICALRow-Level Security в PostgreSQL явно отключена
VGL-RLS002HIGHВ запросе multi-tenant ORM отсутствует фильтр по пользователю или арендатору

Межсайтовый скриптинг (1 правило)

ПравилоУровень критичностиЧто обнаруживает
VGL-XSS001HIGHМежсайтовый скриптинг: небезопасная вставка HTML (CWE-79)

Криптография (1 правило)

ПравилоУровень критичностиЧто обнаруживает
VGL-RAND001HIGHДля значения, критичного с точки зрения безопасности, используется слабый генератор случайных чисел (CWE-330)

Политики IAM (1 правило)

ПравилоУровень критичностиЧто обнаруживает
VGL-IAM001CRITICALВ политике IAM в поле Action или Resource используется подстановочный символ

Python (1 правило)

ПравилоУровень критичностиЧто обнаруживает
VGL-PY001HIGHОбходная проверка отладки не защищена проверкой переменной окружения — аутентификация или проверка безопасности отключается при определённых условиях

Скрипты оболочки (1 правило)

ПравилоУровень критичностиЧто обнаруживает
VGL-S011HIGHСекрет передаётся в subprocess/SSH как аргумент командной строки и может утечь через ps aux

Глубокое сканирование IaC с помощью Trivy (1 правило)

ПравилоУровень критичностиЧто обнаруживает
VGL-T001HIGHГлубокое сканирование IaC с помощью Trivy: неправильные настройки в Dockerfile / Terraform

nginx (1 правило)

ПравилоУровень критичностиЧто обнаруживает
VGL-N001HIGHВ конфигурации nginx отсутствуют заголовки безопасности или используются слабые настройки TLS

Конфигурация

Поместите файл .valcarc в корневую директорию проекта или в любую из родительских директорий:

# .valcarc
disabled_rules = ["VGL-T001"]        # skip trivy scan for this project
min_severity   = "HIGH"              # only report HIGH and above
exclude_paths  = ["vendor", "legacy"]
telemetry      = false               # opt out of anonymous local telemetry

Valca поднимается по дереву директорий в поисках ближайшего файла .valcarc (также поддерживается прежнее имя .vigilrc). Конфигурация дочерней директории всегда имеет приоритет над родительской. В монорепозиториях можно задавать переопределения для отдельных проектов, сохраняя общие настройки по умолчанию для рабочего пространства.

Подавление предупреждения в строке — используйте для конкретной строки, которую вы проверили и решили принять:

auto_approve = True  # vigil: ignore

Принцип тот же, что у # noqa (flake8) и # nosec (bandit).


Отказ от телеметрии

Valca собирает анонимные данные об использовании только локально: идентификатор правила, уровень серьёзности и расширение файла. Пути к файлам, код и идентифицирующие данные не собираются. Данные хранятся в ~/.valca/events.jsonl и никуда не отправляются. История из прежнего расположения ~/.vigil/ переносится автоматически.

Чтобы отключить телеметрию навсегда:

export VALCA_NO_TELEMETRY=1        # VIGIL_NO_TELEMETRY still works

Или добавьте в .valcarc:

telemetry = false

Добавление правила

# src/valca/rules/my_category.py
from pathlib import Path
from .base import Finding, Rule, Severity

class MyRule(Rule):
    id = "VGL-X001"
    name = "Descriptive rule name"
    severity = Severity.HIGH

    def applies_to(self, path: Path) -> bool:
        return path.suffix == ".yml"

    def check(self, path: Path) -> list[Finding]:
        findings = []
        for i, line in enumerate(path.read_text().splitlines(), 1):
            if "bad_pattern" in line:
                findings.append(Finding(
                    rule_id=self.id,
                    severity=self.severity,
                    message="Found bad pattern",
                    file_path=path,
                    line=i,
                    snippet=line.strip(),
                    fix="Do this instead.",
                ))
        return findings

Добавьте правило в DEFAULT_RULES в src/valca/rules/__init__.py и напишите тесты. Готово.


GitHub Actions

Используйте action — PranLabs/valca-action:

permissions:
  contents: read
  security-events: write

steps:
  - uses: actions/checkout@v7

  - uses: PranLabs/valca-action@v1
    with:
      severity: HIGH
      version: "0.6.0"    # pin for reproducible CI

  - uses: github/codeql-action/upload-sarif@v4
    if: always()
    with:
      sarif_file: valca-results.sarif
      category: valca

Можно также запускать Valca напрямую, без action:

- run: pip install valca --quiet
- run: valca scan . --no-color
- run: valca scan . --format sarif > valca-results.sarif

Результаты проверки появятся в виде встроенных комментариев в изменённых строках PR, а также на вкладке Security репозитория.


Сервер MCP

Hook блокирует действия агента, а сервер MCP позволяет агенту запрашивать информацию.

pip install "valca[mcp]"
valca-mcp

Зарегистрируйте сервер в любом MCP-клиенте. Например, для Claude Code используйте claude mcp add valca -- valca-mcp.

Сервер предоставляет два инструмента, оба доступны только для чтения:

ИнструментЧто возвращает
scan(path)Найденные проблемы в файле или каталоге: правило, уровень серьёзности, описание, файл, строка и предлагаемое исправление
list_rules()Полный перечень правил: идентификатор каждого правила, уровень серьёзности и тип выявляемых проблем

Инструментов для редактирования, исправления или записи данных нет. Сканер, способный изменять код, создаёт новую поверхность атаки — именно от таких случаев защищают правила VGL-MCP003 и VGL-MCP005.

В сервере предусмотрены три ограничения, которые нельзя изменить:

  • Сканирование не выходит за пределы корневого каталога. Корневым считается каталог, из которого запущен valca-mcp, или значение VALCA_MCP_ROOT, если оно задано. Агент сам выбирает аргумент для scan, поэтому без такого ограничения он мог бы перейти в ~/.ssh и исследовать файловую систему, доступ к которой ему не предоставляли.

  • Пути возвращаются относительно корневого каталога. Абсолютный путь может раскрыть имя пользователя и структуру каталогов.

  • Совпавшие строки исходного кода не возвращаются. Для правил поиска секретов такая строка и есть секрет.

Телеметрия при работе через сервер MCP отключена независимо от настроек. При этом параметры .valcarc продолжают применяться: disabled_rules, exclude_paths и min_severity.

mcp — необязательный дополнительный компонент, поэтому обычная установка Valca по-прежнему не требует никаких зависимостей во время выполнения.

Hook остаётся механизмом принудительного контроля: он запускается при каждой записи независимо от желания модели. MCP включается агентом по его выбору, а проверка, от которой агент может отказаться, не является принудительным контролем.


Разработка

git clone https://github.com/PranLabs/valca.git
cd vigil
python3 -m venv venv && source venv/bin/activate
pip install -e ".[dev]"
pytest tests/ -v

Лицензия

Лицензия Business Source License 1.1 — бесплатна для некоммерческого использования. Для коммерческого использования требуется лицензионное соглашение. 26 июня 2030 года лицензия автоматически сменится на MIT.


Обратная связь

Нашли ложное срабатывание? Хотите предложить новое правило? Разрабатываете с AI-агентами и сталкиваетесь с ситуациями, которые Valca должна выявлять?

Создайте задачу → github.com/PranLabs/valca/issues

Или выполните команду valca feedback.