Skip to main content

Python SDK for the VulnRadar security scanning API

Project description

VulnRadar Python SDK

A production-ready Python SDK for the VulnRadar security scanning API. Clean, fully typed, and designed for developer-friendly integration.


Overview

VulnRadar scans web targets for security vulnerabilities, exposing findings categorized by severity (critical, high, medium, low, info). This SDK wraps the REST API with:

  • Full type hints and dataclass-based response models
  • Automatic authentication header injection
  • Structured error handling with custom exceptions
  • Rate limit awareness via response header parsing
  • Configurable timeout and retry logic
  • Support for single scans, deep crawl scans, URL discovery, and history retrieval

Installation

pip install vulnradar

Requires Python 3.10+.


Quickstart

from vulnradar import VulnRadar

client = VulnRadar(api_key="your-api-key")

result = client.scan("https://example.com")

print(f"Total findings: {result.summary.total}")
print(f"Critical: {result.summary.critical}")

for finding in result.findings:
    print(f"[{finding.severity.value.upper()}] {finding.title}")

Authentication

All requests are authenticated using a Bearer token in the Authorization header. Pass your API key when constructing the client:

client = VulnRadar(api_key="your-api-key")

Configuration

client = VulnRadar(
    api_key="your-api-key",
    timeout=60,          # HTTP timeout in seconds (default: 30)
    retries=5,           # Retry attempts on server errors (default: 3)
    base_url="https://vulnradar.dev/api/v1",  # Custom base URL (optional)
)

Running Scans

Single URL Scan

result = client.scan("https://example.com")

print(result.url)
print(result.scanned_at)
print(result.duration)
print(result.scan_history_id)

for finding in result.findings:
    print(finding.type, finding.severity, finding.title)
    print(finding.description)
    print(finding.remediation)

ScanResult fields:

Field Type Description
url str Scanned URL
scanned_at datetime Timestamp of the scan
duration float Scan duration in seconds
findings list[Finding] List of security findings
summary Summary Aggregated finding counts
response_headers dict[str, str] HTTP headers from the target
scan_history_id str | None ID in scan history
notes str | None Optional scan notes

Crawl Scans

Perform a deep crawl across multiple pages of a target:

result = client.scan_crawl("https://example.com")

print(f"Pages scanned: {result.crawl.total_pages}")
print(f"Total findings: {result.crawl.total_findings}")

for page in result.pages:
    print(f"{page.url}{page.summary.total} findings")

You can also provide a list of specific URLs to include:

result = client.scan_crawl(
    "https://example.com",
    urls=["https://example.com/login", "https://example.com/admin"],
)

Discover URLs

Discover all crawlable URLs for a target before running a crawl scan:

discovery = client.discover_urls("https://example.com")

print(f"Found {discovery.total} URLs")
for url in discovery.urls:
    print(url)

Scan History

List Recent Scans

history = client.history.list()

for scan in history.scans:
    print(scan.id, scan.url, scan.scanned_at)
    print(f"  Findings: {scan.findings_count}")

Get a Specific Scan

result = client.history.get("scan-id-here")

print(result.url)
for finding in result.findings:
    print(finding.title, finding.severity)

Finding Types

Retrieve the full catalog of supported finding types:

catalog = client.metadata.finding_types()

print(f"Version: {catalog.version}")
print(f"Total types: {catalog.count}")

for ft in catalog.types:
    print(f"[{ft.severity.value}] {ft.title} ({ft.category})")

Version Check

info = client.version()

print(info.current)
print(info.latest)
print(info.engine)
print(info.status)

Error Handling

All exceptions inherit from VulnRadarError:

from vulnradar import (
    VulnRadar,
    VulnRadarError,
    AuthenticationError,
    BadRequestError,
    NotFoundError,
    RateLimitError,
    ServerError,
    InvalidURLError,
)

client = VulnRadar(api_key="your-api-key")

try:
    result = client.scan("https://example.com")
except InvalidURLError as e:
    print(f"Bad URL: {e.url}")
except AuthenticationError:
    print("Invalid or expired API key.")
except RateLimitError as e:
    print(f"Rate limited. Resets at: {e.resets_at}")
    print(f"Limit: {e.limit}, Remaining: {e.remaining}")
except NotFoundError:
    print("Resource not found.")
except ServerError as e:
    print(f"Server error {e.status_code}: {e.message}")
except VulnRadarError as e:
    print(f"SDK error: {e.message}")

Exception Reference

Exception HTTP Status Description
AuthenticationError 401 Invalid or missing API key
BadRequestError 400 Malformed request or invalid params
NotFoundError 404 Requested resource does not exist
RateLimitError 429 Rate limit exceeded
ServerError 5xx API-side internal error
InvalidURLError URL failed client-side validation

Rate Limits

The SDK automatically parses rate limit headers from every response. When you hit a rate limit, the RateLimitError exception exposes:

except RateLimitError as e:
    print(e.limit)       # Total allowed requests
    print(e.used)        # Requests used
    print(e.remaining)   # Requests remaining
    print(e.resets_at)   # datetime when limit resets

Headers parsed:

  • X-RateLimit-Limit
  • X-RateLimit-Remaining
  • X-RateLimit-Reset
  • Retry-After

Severity Enum

from vulnradar import Severity

Severity.CRITICAL  # "critical"
Severity.HIGH      # "high"
Severity.MEDIUM    # "medium"
Severity.LOW       # "low"
Severity.INFO      # "info"

Filter findings by severity:

critical = [f for f in result.findings if f.severity == Severity.CRITICAL]

Best Practices

Handle rate limits gracefully:

import time
from vulnradar import VulnRadar, RateLimitError

client = VulnRadar(api_key="your-api-key")

def safe_scan(url: str):
    try:
        return client.scan(url)
    except RateLimitError as e:
        if e.resets_at:
            wait = (e.resets_at - datetime.now(timezone.utc)).total_seconds()
            time.sleep(max(wait, 1))
        return client.scan(url)

Use history to avoid redundant scans:

history = client.history.list()
already_scanned = {s.url for s in history.scans}

if target_url not in already_scanned:
    result = client.scan(target_url)

Pre-discover URLs before crawling:

discovery = client.discover_urls("https://example.com")
if discovery.total > 0:
    result = client.scan_crawl("https://example.com", urls=discovery.urls)

Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Make your changes with full type hints
  4. Run tests: pytest
  5. Submit a pull request

All contributions must pass lint and type checking.


License

MIT — see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vulnradar-0.1.0.tar.gz (15.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vulnradar-0.1.0-py3-none-any.whl (20.2 kB view details)

Uploaded Python 3

File details

Details for the file vulnradar-0.1.0.tar.gz.

File metadata

  • Download URL: vulnradar-0.1.0.tar.gz
  • Upload date:
  • Size: 15.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.21 {"installer":{"name":"uv","version":"0.9.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for vulnradar-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a69689fd49b26af100c867c8777f2fd628570b731c0105dc9fee0628c94b91f0
MD5 d1c32cb3f6148cd70ec884306805bc55
BLAKE2b-256 afc7b890af1580353f63bb1833fc002bffad4f1d3e408a8252f57c6d86a39c4b

See more details on using hashes here.

File details

Details for the file vulnradar-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: vulnradar-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 20.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.21 {"installer":{"name":"uv","version":"0.9.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for vulnradar-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6c7f4e5ccba3875062261f43e1f08ed3a97b7b0fc35f2d946188bfa4d4b7d2e8
MD5 0378caa4b499c92d103ab33125e17bf9
BLAKE2b-256 cd5ca95641d226fc6954becbe559c44d366daf4d06d222cb77ea3a4235b1c362

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page