nuclei-sdk (Python)
Async Python client for the Nuclei scanning engine, built by RevoltSecurities.
Same architecture as the Go SDK: one engine setup, many lightweight concurrent scans. Built on asyncio for maximum scalability — coroutines use ~1KB each vs ~8MB per thread.
Installation
pip install nuclei-sdk
The Go bridge binary (nuclei-sdk-bridge) is auto-installed from GitHub Releases on first use — no Go toolchain required. Supports Linux, macOS, and Windows on amd64/arm64.
Quick Start
import asyncio
from nucleisdk import ScanEngine
async def main():
# Binary auto-downloads if not found — zero setup needed
engine = ScanEngine(rate_limit=100, timeout=10, no_interactsh=True)
await engine.setup()
async for result in engine.scan(targets=["https://example.com"], tags=["cve"], severities=["high"]):
print(f"[{result.severity}] {result.template_id} - {result.matched_url}")
await engine.close()
asyncio.run(main())
Async Context Manager
async with ScanEngine(rate_limit=100, no_interactsh=True) as engine:
results = [r async for r in engine.scan(targets=["https://example.com"])]
Multiple Scans (Same Engine)
async with ScanEngine(rate_limit=100) as engine:
# Scan 1 — HTTP CVEs
async for r in engine.scan(targets=["https://a.com"], tags=["cve"], protocol_types="http"):
print(r.template_id)
# Scan 2 — SSL checks (same engine, no re-initialization)
async for r in engine.scan(targets=["b.com:443"], protocol_types="ssl"):
print(r.template_id)
ScanPool: Continuous Dynamic Scanning
Iterator Mode
from nucleisdk import ScanEngine, TemplateBytesEntry
async def main():
async with ScanEngine(rate_limit=100, no_interactsh=True) as engine:
pool = await engine.scan_pool(workers=5)
# Submit jobs dynamically
await pool.submit("CVE-2024-1234",
targets=["https://target.com"],
template_bytes=[TemplateBytesEntry("CVE-2024-1234", yaml_bytes)])
await pool.submit("wordpress",
targets=["https://wp.example.com"],
tags=["wordpress"])
# Consume results
async for lr in pool.results():
print(f"[{lr.label}] [{lr.result.severity}] {lr.result.template_id}")
await pool.close()
stats = await pool.stats()
print(f"Submitted: {stats.submitted}, Completed: {stats.completed}")
Callback Mode (No Manual Iteration)
async def handle_result(lr):
print(f"[{lr.label}] [{lr.result.severity}] {lr.result.template_id}")
async def main():
async with ScanEngine(rate_limit=100, no_interactsh=True) as engine:
pool = await engine.scan_pool(workers=5, on_result=handle_result)
await pool.submit("CVE-2024-1234", targets=["https://target.com"], ...)
await pool.submit("wordpress", targets=["https://wp.example.com"], tags=["wordpress"])
await pool.close() # waits for all jobs; callback fires automatically
Concurrent Submit + Consume with asyncio.gather
async def submit_jobs(pool):
for cve in cve_feed:
await pool.submit(cve["id"], targets=[cve["target"]], template_bytes=[...])
await pool.close()
async def consume_results(pool):
async for lr in pool.results():
print(f"[{lr.label}] {lr.result.severity}")
async def main():
async with ScanEngine(rate_limit=100, no_interactsh=True) as engine:
pool = await engine.scan_pool(workers=10)
await asyncio.gather(submit_jobs(pool), consume_results(pool))
Targeted Scan with Template Bytes
from nucleisdk import ScanEngine, TemplateBytesEntry
yaml_template = b"""
id: custom-check
info:
name: Custom Check
severity: high
author: me
http:
- method: GET
path:
- "{{BaseURL}}/admin"
matchers:
- type: status
status:
- 200
"""
async def main():
async with ScanEngine(no_interactsh=True) as engine:
async for r in engine.scan(
targets=["https://example.com"],
template_bytes=[TemplateBytesEntry("custom-check", yaml_template)]
):
print(f"[{r.severity}] {r.template_id}")
Bridge Binary Installation
The bridge binary is auto-installed on first use. You can also manage it manually:
Auto-Install (Default)
# Just use ScanEngine — binary is downloaded automatically if not found
async with ScanEngine(rate_limit=100) as engine:
...
Output on first run:
nucleisdk: nuclei-sdk-bridge not found locally, attempting auto-install from GitHub Releases...
nucleisdk: fetching latest release from RevoltSecurities/nuclei-sdk...
nucleisdk: latest release: v0.1.0
nucleisdk: downloading nuclei-sdk-bridge_0.1.0_darwin_arm64.tar.gz...
nucleisdk: checksum verified.
nucleisdk: installed nuclei-sdk-bridge v0.1.0 to /home/user/.local/bin/nuclei-sdk-bridge
Manual Install
from nucleisdk import install_bridge
# Install to default location (~/.local/bin/ on Linux/macOS)
path = install_bridge()
print(f"Installed to: {path}")
# Install to a custom directory
path = install_bridge(install_dir="/opt/nuclei/bin")
Quiet Mode (No Logging)
from nucleisdk import install_bridge
# Suppress all installation progress messages
path = install_bridge(quiet=True)
Custom Repository (Forks)
from nucleisdk import install_bridge
# Install from a fork — only 'owner/repo' format allowed
path = install_bridge(repo="MyOrg/my-nuclei-fork")
# Combined with other options
path = install_bridge(
repo="MyOrg/my-nuclei-fork",
install_dir="/opt/nuclei/bin",
quiet=True,
)
Only GitHub URLs are accepted — full URLs, path traversal, and query injection are all rejected with InstallError (SSRF protection).
Use a Specific Binary
# Skip auto-install entirely — use your own binary
engine = ScanEngine(
binary_path="/opt/homebrew/bin/nuclei-sdk-bridge",
rate_limit=100,
)
Build From Source (Alternative)
# Requires Go toolchain
cd /path/to/nuclei-sdk
go build -o bin/nuclei-sdk-bridge ./cmd/nuclei-sdk-bridge/
Error Handling
from nucleisdk import (
ScanEngine,
InstallError,
DownloadError,
ChecksumError,
UnsupportedPlatformError,
InstallPermissionError,
)
try:
async with ScanEngine() as engine:
...
except UnsupportedPlatformError:
# OS/arch not in pre-built releases (e.g., FreeBSD, 32-bit)
print("Build from source: go build -o bin/nuclei-sdk-bridge ./cmd/nuclei-sdk-bridge/")
except DownloadError:
# No internet, GitHub down, rate limited
print("Check internet connection or use binary_path=")
except ChecksumError:
# Downloaded file corrupted — retry
print("Download corrupted, try again")
except InstallPermissionError:
# Can't write to ~/.local/bin/
print("Use install_bridge(install_dir='./bin') for a writable path")
except InstallError:
# Catch-all for any install failure
print("Installation failed")
Install Locations
| Platform | Default Path |
|---|---|
| Linux | ~/.local/bin/nuclei-sdk-bridge |
| macOS | ~/.local/bin/nuclei-sdk-bridge |
| Windows | %LOCALAPPDATA%\nuclei-sdk\bin\nuclei-sdk-bridge.exe |
Exception Hierarchy
BridgeError
└── InstallError
├── UnsupportedPlatformError
├── DownloadError
├── ChecksumError
├── InstallPermissionError
└── VersionMismatchError
Version Management
The Python SDK automatically checks bridge binary version compatibility on startup.
Automatic Version Check
# Version is checked automatically when ScanEngine starts.
# If the installed binary is incompatible, a compatible one is auto-downloaded.
async with ScanEngine(rate_limit=100) as engine:
...
Check Version Manually
from nucleisdk import ensure_bridge, get_bridge_version, check_version_compatible, MIN_BRIDGE_VERSION
path = ensure_bridge(quiet=True)
ver = get_bridge_version(path)
print(f"Bridge version: {ver}")
print(f"Compatible: {check_version_compatible(ver)}")
print(f"Min required: {MIN_BRIDGE_VERSION}")
Force Update
from nucleisdk import install_bridge
# Always downloads the latest version, even if current is compatible
path = install_bridge(update=True)
Handle Version Mismatch
from nucleisdk import ensure_bridge, install_bridge, VersionMismatchError
try:
path = ensure_bridge(auto_install=False)
except VersionMismatchError as e:
print(f"Incompatible bridge: {e}")
path = install_bridge(update=True)
API Reference
ScanEngine
| Method | Description |
|---|---|
ScanEngine(**config) |
Create engine with config (rate_limit, timeout, tags, etc.) |
await setup() |
One-time heavy initialization |
async for r in scan(**opts) |
Lightweight scan, yields ScanResult |
await scan_collect(**opts) |
Same as scan(), returns List[ScanResult] |
await scan_pool(workers, on_result=None) |
Create a ScanPool |
await close() |
Shut down engine |
async with ScanEngine() as engine |
Context manager (auto setup/close) |
ScanPool
| Method | Description |
|---|---|
await submit(label, **opts) |
Queue a scan job |
async for lr in results() |
Iterate over LabeledResult |
await stats() |
Get PoolStats |
await close() |
Wait for jobs and shut down |
ScanResult
| Field | Type | Description |
|---|---|---|
template_id |
str | Template identifier |
severity |
str | info, low, medium, high, critical |
matched_url |
str | URL that matched |
host |
str | Target host |
tags |
List[str] | Template tags |
cve_id |
List[str] | CVE identifiers |
is_critical() |
bool | Severity == critical |
is_high_or_above() |
bool | Severity >= high |
severity_level() |
int | 0-5 numeric |
Installer & Version
| Function | Description |
|---|---|
install_bridge(install_dir=None, quiet=False, repo=..., update=False) |
Download and install the bridge binary |
ensure_bridge(binary_path=None, quiet=False, auto_install=True, update=False, repo=...) |
Find or auto-install a compatible bridge binary |
get_bridge_version(binary_path) |
Get version string from a bridge binary |
check_version_compatible(version) |
Check if a version meets SDK requirements |
| Parameter | Type | Default | Description |
|---|---|---|---|
install_dir |
str | None | None |
Custom install directory (default: ~/.local/bin/) |
quiet |
bool | False |
Suppress installation progress messages |
repo |
str | "RevoltSecurities/nuclei-sdk" |
GitHub owner/repo to fetch from (SSRF-safe) |
update |
bool | False |
Always download latest version |
auto_install |
bool | True |
Auto-download if not found or incompatible |
License
MIT
Metadata
Release files for nuclei-sdk 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nuclei_sdk-1.1.0.tar.gz | 24.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nuclei_sdk-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 51.2 kB
Release files / nuclei_sdk-1.1.0.tar.gz
| Download URL | nuclei_sdk-1.1.0.tar.gz |
|---|---|
| Size | 24.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c7ddb0c80bb2fc5e277b7ab9f186f3f0c265a6c82cf2403a5258637f3314c3ad
|
|
BLAKE2b-256 checksum How to use checksums |
948f39c5d5ec77dbf9d638b0e80d0e851a0601baf29c0925d4c0dc37473c46d2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.4 {"installer":{"name":"uv","version":"0.11.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / nuclei_sdk-1.1.0-py3-none-any.whl
| Download URL | nuclei_sdk-1.1.0-py3-none-any.whl |
|---|---|
| Size | 26.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
326531452ad91d35ab8ac888287feb9d00ba34da027bbc9a914088e2debdbd10
|
|
BLAKE2b-256 checksum How to use checksums |
5df3b4d0052998712954621251cc2232bb377ff4f05b359f1576a718bec131fb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.4 {"installer":{"name":"uv","version":"0.11.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|