Полное руководство по сканеру Nuclei

Полное руководство по сканеру Nuclei

Уязвимость редко выглядит как нечто сложное. Чаще всего это забытая доступная всем дирректория /debug, старая версия CMS, открытый конфигурационный файл .env, лишний заголовок или API, которое доверяет параметру из запроса. Для бизнеса такая мелочь быстро превращается в утечку данных, простой сервиса или входную точку во внутреннюю сеть. В связи с этим встает вопрос: как найти уязвимость веб приложения быстрее хакера? Один из множества ответов на этот вопрос являеться сканнер уязвимостей Nuclei.

Nuclei - это быстрый сканер уязвимостей от ProjectDiscovery. Он работает по YAML-шаблонам. В шаблоне описано, что отправить приложению, какой ответ считать подозрительным и какую критичность присвоить находке. Nuclei используеться как сканер для приложений, инфраструктуры, облаков и сетевых сервисов. Сканер помогает увидеть повторяющиеся классы проблем. WAF снижает риск эксплуатации. 

В этой статье мы разберем, как поставить Nuclei, как запускать базовые и точечные проверки, какие уязвимости он хорошо находит, как писать свои шаблоны, как проверять авторизованные зоны, как встроить сканирование в CI/CD и как использовать Check Risk WAF как защитный контур. 

Где Nuclei полезен, а где его нельзя переоценивать

Nuclei не заменяет анализа кода, пентеста и процесса управления уязвимостями. Он закрывает другую задачу. Он быстро проверяет известные признаки уязвимостей на большом числе целей.

У Nuclei есть сильная сторона. Шаблоны которые используются в системе можно создовать, просматривать и модифицировать под свои задачи. В отчете виден путь запроса, условия совпадения, теги, severity и логику проверки. В официальном репозитории nuclei-templates на 31 мая 2026 года указаны тысячи шаблонов. Среди популярных тегов есть vuln, cve, discovery, xss, wordpress, exposure, а для активно эксплуатируемых уязвимостей проект предлагает запуск по тегам kev,vkev.

Но нужно понимать, что результат Nuclei надо проверять и подтверждать как и результаты любого другого сканера уязвимостей, поскольку сканер может дать ложное срабатывание. Или наоборот не увидеть проблему, если она скрыта за авторизацией, нестандартным маршрутом, бизнес-логикой или защитой на уровне приложения.

Внимание: запускать проверки нужно только по своим системам или по письменному разрешению. Даже “безопасный” шаблон создает сетевой трафик. DAST и fuzz-режимы могут менять нагрузку на сервис.

Установка и первый запуск

Установка Nuclei кросс платформена и очень проста. Есть также Homebrew, Docker, бинарные сборки и Helm варианты инсталяции.

# команда устанавливает Nuclei через Go
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest

# команда устанавливает Nuclei через Homebrew
brew install nuclei

# команда скачивает Docker образ Nuclei
docker pull projectdiscovery/nuclei:latest

# команда показывает установленную версию
nuclei -version

# команда обновляет движок Nuclei
nuclei -update

# команда обновляет набор шаблонов
nuclei -update-templates

Самый простой запуск сканирования выглядит так:

# команда запускает проверку одного веб-приложения стандартными шаблонами
nuclei -u https://app.example.com

Для рабочих проверок лучше сразу ограничить критичность и сохранить отчет.

# команда запускает проверку только high и critical находок
nuclei -u https://app.example.com -severity high,critical -o nuclei-high.txt

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

# команда создает файл целей для сканирования
printf "https://app.example.com\nhttps://api.example.com\n" > targets.txt

# команда запускает проверку списка целей по CVE, утечкам и ошибкам конфигурации
nuclei -l targets.txt -tags cve,exposure,misconfig -severity medium,high,critical -rl 25 -c 10 -bs 10 -jle nuclei.jsonl

Здесь -l читает цели из файла, -tags выбирает группы шаблонов, -severity режет шум, -rl ограничивает запросы в секунду, -c управляет параллельным выполнением шаблонов, -bs управляет числом хостов на шаблон, а -jle сохраняет результат в JSONL. Эти флаги есть в официальной справке Nuclei.

Теперь можно перейти к тому, что именно стоит искать.

Устаревшие компоненты и CVE

Самая понятная группа проблем - известные уязвимости в продуктах. Это CMS, VPN-панели, админки, Java-фреймворки, плагины, панели мониторинга, API-шлюзы. Атакующему не всегда нужен новый эксплойт. Часто хватает публичного CVE и сервиса, который не обновляли месяцами.

Nuclei хорошо подходит для первичного поиска таких целей. Он не просто смотрит баннер версии. Хороший шаблон проверяет характерный endpoint, заголовок, текст ответа или безопасный признак уязвимого поведения.

# команда запускает проверку CVE по списку целей
nuclei -l targets.txt -tags cve -severity high,critical -o cve-report.txt

# команда запускает проверку уязвимостей из KEV и VulnCheck KEV тегов
nuclei -l targets.txt -tags kev,vkev -severity high,critical -o kev-report.txt

# команда выводит список шаблонов, которые будут выбраны фильтрами
nuclei -tags cve -severity high,critical -tl

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

Check Risk WAF тут полезен как слой с быстрым временем реакции. Когда патч еще тестируется, WAF может заблокировать запросы к известному уязвимому пути, ограничить методы, закрыть подозрительные payload-структуры и отдать событие в журнал.

Раскрытие данных и ошибки конфигурации

Открытый конфигурационный файл .env, листинг директории, публичный backup, debug-страница, Swagger без авторизации, панель администратора снаружи - все это и многие другие ошибки конфигурации может привести к утечки конфиденциальных данных.

OWASP Top 10 2025 ставит Security Misconfiguration на второе место, а Software Supply Chain Failures на третье. В том же списке остаются Broken Access Control, Injection, Cryptographic Failures и Authentication Failures. Это хороший ориентир для того, какие классы проблем стоит проверять регулярно.

Проверка через Nuclei:

# команда ищет раскрытие данных, панели и ошибки конфигурации
nuclei -l targets.txt -tags exposure,panel,misconfig -severity low,medium,high,critical -o exposure-report.txt

# команда ищет технологические признаки приложения
nuclei -u https://app.example.com -tags tech -silent

# команда исключает информационные шаблоны и снижает шум
nuclei -l targets.txt -tags exposure,misconfig -exclude-severity info -o clean-exposure.txt

Пример типовой ошибки в Node.js:

app.get('/debug', (req, res) => {
  res.json({
    env: process.env,
    stack: lastErrorStack
  })
})

Проблема простая. Приложение отдает переменные окружения. Там часто лежат конфиденциальные данные, строки подключения к БД, ключи API и внутренние адреса.

Пример защиты кода:

app.get('/debug', requireAdmin, (req, res) => {
  if (process.env.NODE_ENV === 'production') {
    return res.status(404).json({error: 'not found'})
  }

  res.json({
    status: 'ok'
  })
})

Дополнительно стоит включить защитные заголовки. Например через helmet в Express.

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      frameAncestors: ["'none'"]
    }
  },
  referrerPolicy: {
    policy: 'strict-origin-when-cross-origin'
  }
}))

Check Risk WAF здесь можно настроить на блокировку доступа к типовым опасным путям вроде .env, .git, backup, debug, server-status. Еще полезно включить правило, которое не пропускает ответы с признаками секретов в body, если продукт поддерживает такую проверку. Но лучше не хранить секреты там, откуда веб-сервер вообще может их отдать.

SQL-инъекции и похожие инъекции

Инъекция появляется, когда данные пользователя становятся частью команды. Это может быть SQL, LDAP, XPath, shell-команда или шаблон. В веб-приложениях чаще всего встречается SQL-инъекция. В OWASP Top 10 2025 Injection остается отдельной критичной категорией.

Пример уязвимого кода:

app.get('/user', async (req, res) => {
  const id = req.query.id

  const result = await db.query(
    `select id, email from users where id = ${id}`
  )

  res.json(result.rows)
})

Здесь id попадает прямо в SQL. База не понимает, где данные, а где часть запроса.

Поиск SQL inj через Nuclei:

# команда запускает шаблоны с тегами sqli и injection
nuclei -u https://app.example.com -tags sqli,injection -severity medium,high,critical -o injection.txt

# команда запускает DAST fuzz-проверки на staging с низкой агрессивностью
nuclei -u https://staging.example.com -dast -fa low -cs '^https://staging\.example\.com' -rl 5 -o dast-low.txt

Флаг -dast включает fuzz-шаблоны. Его лучше запускать на staging или в согласованное окно. В справке Nuclei fuzz-режим указан как DAST, а старый -fuzz помечен как deprecated.

Исправление SQL-инъекции:

app.get('/user', async (req, res) => {
  const id = Number(req.query.id)

  if (!Number.isInteger(id)) {
    return res.status(400).json({error: 'bad id'})
  }

  const result = await db.query(
    'select id, email from users where id = $1',
    [id]
  )

  res.json(result.rows)
})

Тут работают две вещи. Сначала проверяется тип. Потом SQL выполняется с параметром $1. Данные остаются данными.

Check Risk WAF может блокировать признаки SQL-инъекций на входе. Это полезно, когда уязвимость уже найдена, а исправление проходит релизный цикл. Но WAF не знает бизнес-смысл запроса так же хорошо, как приложение. Поэтому правильная защита - параметризованные запросы, валидация входа и минимальные права учетной записи БД.

XSS и опасный вывод данных

XSS возникает, когда приложение возвращает пользовательский ввод как исполняемый HTML или JavaScript. Последствия уязвисти зависят от контекста ее расположения. Это может быть кража сессии, действие от имени пользователя, подмена интерфейса или атака на админ-панель.

Уязвимый пример в React:

function Comment({html}) {
  return <div dangerouslySetInnerHTML={{__html: html}} />
}

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

Безопасный вариант кода так:

function Comment({text}) {
  return <p>{text}</p>
}

React по умолчанию экранирует текст в JSX. Если HTML реально нужен, его надо чистить через проверенную библиотеку и ограничивать разрешенные теги.

Поиск XSS через Nuclei:

# команда запускает XSS-шаблоны
nuclei -u https://app.example.com -tags xss -severity medium,high,critical -o xss.txt

# команда включает headless-шаблоны, которым нужен браузерный режим
nuclei -u https://app.example.com -headless -tags xss -rl 5 -o xss-headless.txt

Обратите внимание: некоторые шаблоны Nuclei не запускаются по умолчанию. Для browser-based проверок нужен -headless, для code-шаблонов нужен -code, для DAST нужен отдельный режим. Это сделано, чтобы пользователь случайно не запустил тяжелые или более рискованные проверки.

Check Risk WAF хорошо подходит для фильтрации частых XSS-паттернов. Он анализирует HTTP-запросы и применяет правила к трафику. OWASP описывает WAF как firewall для HTTP-приложений, который защищает серверы и обычно покрывает атаки вроде XSS и SQL Injection.

SSRF и доступ к внутренним ресурсам

SSRF появляется, когда сервер берет URL из запроса пользователя и сам идет по этому URL. Внешне это выглядит как полезная функция: “загрузить картинку”, “проверить webhook”, “импортировать файл”. Проблема в том, что сервер видит внутреннюю сеть. Пользователь снаружи может заставить его обратиться к внутреннему адресу.

OWASP API Security Top 10 2023 описывает SSRF именно так: API получает пользовательский URI без достаточной проверки и делает запрос в неожиданное место, даже если ресурс спрятан за firewall или VPN.

Уязвимый пример на Python:

@app.get('/fetch')
def fetch():
    url = request.args.get('url')
    response = requests.get(url, timeout=3)
    return response.text

Защита:

from urllib.parse import urlparse
import socket
import ipaddress

ALLOWED_HOSTS = {'api.partner.example'}

def is_public_ip(hostname):
    ip = ipaddress.ip_address(socket.gethostbyname(hostname))
    return not (
        ip.is_private or
        ip.is_loopback or
        ip.is_link_local
    )

def is_allowed_url(raw):
    parsed = urlparse(raw)

    if parsed.scheme != 'https':
        return False

    if parsed.hostname not in ALLOWED_HOSTS:
        return False

    return is_public_ip(parsed.hostname)

@app.get('/fetch')
def fetch():
    url = request.args.get('url')

    if not is_allowed_url(url):
        return {'error': 'blocked'}, 400

    response = requests.get(url, timeout=3)
    return response.text

Поиск SSRF через Nuclei:

# команда запускает SSRF-шаблоны по целевому приложению
nuclei -u https://app.example.com -tags ssrf -severity medium,high,critical -o ssrf.txt

Check Risk WAF может помочь на входе. Например заблокировать запросы, где параметры URL указывают на localhost, private IP, cloud metadata endpoints или нестандартные схемы. Но реальная граница защиты должна быть в приложении и сети: allowlist доменов, запрет приватных IP, короткие timeout, отключение редиректов, отдельный egress-proxy и правила исходящего трафика.

Авторизованные проверки

Большая часть интересных уязвимостей находиться в панелях после авторизации. Без авторизации сканер видит только внешний контур веб приложения. Nuclei поддерживает authenticated scans через Secret File. В нем можно описать Basic Auth, Bearer Token, cookie, query token и custom headers.

Внимание: хорошей практикой являеться ограничивать scope секрета, чтобы не отправить токен третьей стороне.

Пример Secret File файла:

static:
  - type: bearertoken
    domains:
      - api.example.com
    token: replace_with_ci_secret

Запуск сканирования nuclei с авторизацией:

# команда запускает проверку API с файлом авторизации
nuclei -u https://api.example.com -sf nuclei-secrets.yaml -severity high,critical -o auth-scan.txt

Для реального проекта секреты не кладут в репозиторий. Их передают из CI secrets, Vault или другого хранилища. Логи Nuclei тоже надо чистить. Для этого пригодится -redact.

# команда скрывает чувствительные поля в сохраненных результатах
nuclei -u https://api.example.com -sf nuclei-secrets.yaml -redact authorization,cookie,token -jle auth.jsonl

Свои шаблоны без смс и регистрации

Профессиональное использование Nuclei начинается там, где готовых шаблонов мало. У каждой компании есть свои “любимые” ошибки. Например debug endpoint, тестовый header, открытая ручка healthcheck с версией приложения или старый внутренний путь.

Пример простого шаблона Nuclei:

id: app-debug-enabled

info:
  name: App debug endpoint is exposed
  author: security-team
  severity: medium
  tags: exposure,debug

http:
  - method: GET
    path:
      - "{{BaseURL}}/debug"

    matchers-condition: and
    matchers:
      - type: status
        status:
          - 200

      - type: word
        part: body
        words:
          - "environment"
          - "stack"
        condition: or

Проверка и запуск своего шаблона:

# команда проверяет синтаксис шаблона
nuclei -validate -t custom/app-debug-enabled.yaml

# команда запускает собственный шаблон по staging
nuclei -u https://staging.example.com -t custom/app-debug-enabled.yaml -o custom.txt

Внимание: c code-шаблонами надо быть осторожнее. Nuclei поддерживает выполнение внешнего кода на хосте, где запущен сканер. В документации отдельно сказано, что это несет риск, а unsigned code templates не выполняются.

# команда запрещает запуск неподписанных шаблонов
nuclei -l targets.txt -dut -severity high,critical -o signed-only.txt

Предупреждение: на практике я бы не запускал чужие code-шаблоны на рабочей машине без ручной проверки. Для них лучше создовать отдельный контейнер, минимум прав, отдельную сеть.

CI/CD и рабочий процесс команды

Nuclei хорошо ложится в pipeline. Его можно запускать после деплоя staging, перед релизом или по расписанию. Официальная документация показывает GitHub Action projectdiscovery/nuclei-action@v3, запуск по push и pull request, а также экспорт SARIF для GitHub Code Scanning.

Минимальный пример:

name: nuclei-scan

on:
  pull_request: {}

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Nuclei
        uses: projectdiscovery/nuclei-action@v3
        with:
          args: -u https://staging.example.com -severity high,critical -jle nuclei.jsonl

Я бы не валил сборку на любую medium находку. Иначе команда быстро начнет игнорировать сканер. Рабочая выглядет схема проще: critical и подтвержденные high блокируют релиз, medium уходит в backlog, info используется для инвентаризации.

Check Risk WAF здесь становится частью цикла. Nuclei находит проблему. Команда подтверждает ее. Разработчик чинит код. WAF получает временное правило или виртуальный патчинг. После релиза Nuclei запускают повторно. Если находка ушла, правило в WAF можно ослабить или оставить как дополнительный контроль.

Комплексные рекомендации

  • Сканируйте только согласованные цели. Ведите scope-файл и исключения. Это снижает юридический риск и защищает чужую инфраструктуру.
  • Обновляйте Nuclei и шаблоны перед проверками. Старые шаблоны хуже видят свежие CVE и чаще дают шум.
  • Не запускайте DAST и headless-проверки на продакшене без окна. Они создают больше запросов и могут задеть нестабильные функции.
  • Ограничивайте скорость через -rl, -c, -bs. Сканер должен помогать, а не устраивать нагрузочное тестирование без плана.
  • Проверяйте находки вручную. Отчет сканера - это сигнал, а не готовый инцидент.
  • Храните секреты вне репозитория. Для авторизованных проверок используйте CI secrets или секрет-хранилище.
  • Пишите свои шаблоны для типовых ошибок вашей команды. Это быстрее, чем ждать, пока такая проверка появится в публичном наборе.
  • Закрывайте причину в коде. WAF снижает риск эксплуатации, но не делает уязвимый код безопасным.
  • Логируйте события WAF и Nuclei в одно место. Так проще увидеть, что найденная уязвимость уже кто-то пробует атаковать.

Итог

Nuclei хорош не тем, что “находит все”. Он хорош тем, что быстро и повторяемо проверяет известные классы проблем. Его сила раскрывается в системе: инвентаризация, обновленные шаблоны, авторизованные проверки, свои YAML-шаблоны, CI/CD, ручная валидация и понятный процесс исправления.

Безопасность держится на двух вещах. Первая - правильно настроенные и исправленные системы. Вторая - защитный контур, который снижает риск, пока код меняется. Check Risk WAF уместен именно как такой контур: фильтровать опасный HTTP-трафик, закрывать известные пути эксплуатации, давать журнал событий.

Начните с малого: соберите список внешних веб-целей, обновите Nuclei, прогоните cve, exposure, misconfig, разберите high и critical, затем добавьте проверки в pipeline. После этого сканер перестанет быть разовой утилитой и станет частью нормального прочесса поиска и контроля уязвимостей веб приложений.

Инструменты
114
31.05.2026 15:00
ИП Елисеев Иван Владимирович
ИНН: 236401038208
Свидетельство о государственной регистрации программы для ЭВМ № 2026683774 от 04 августа 2026 г.
Продукт включен в реестр Российского ПО. Реестровая запись №32239 от 17.02.2026 г.
Регистрационный номер оператора, осуществляющего обработку персональных данных: 23-26-176186