Skip to content

ValtersIT CVE & Threat-IP API: Querying, Filtering and Automating Vulnerability Data

Most CVE data sources give you an ID, a score, and a description. The ValtersIT API gives you what you need to act: CVSS vector, EPSS exploitation probability, CISA KEV membership, whether a public exploit or Nuclei template exists, affected version strings, Shodan dorks for exposed instances, YARA/Wazuh/Elastic/Sigma detection rules (on paid plans), and the raw PoC where one exists (Pro). This guide covers every endpoint, every filter, every response field, and the code to use them.

Base URL: https://api.valtersit.com/api/v1
Auth: Authorization: Bearer <your key>

API keys look like vit_v1_xxxxxxxxxxxxxxxxxxxxxxxx. Every request requires the Authorization header — there is no public unauthenticated access. A sandbox key (vit_sandbox_free_demo_key_2026) is available for testing CVE lookups; it returns fixed demo data and returns 403 on IP feed and scan submission endpoints.

Terminal window
# Test authentication
curl -s "https://api.valtersit.com/api/v1/cve/CVE-2024-44000" \
-H "Authorization: Bearer vit_sandbox_free_demo_key_2026" | jq .
import urllib.request, json
BASE = "https://api.valtersit.com/api/v1"
KEY = "vit_v1_your_key_here"
HEADERS = {"Authorization": f"Bearer {KEY}"}
def get(path, params=None):
url = BASE + path
if params:
from urllib.parse import urlencode
url += "?" + urlencode(params)
req = urllib.request.Request(url, headers=HEADERS)
with urllib.request.urlopen(req) as r:
return json.loads(r.read())

GET /api/v1/cve — list CVE records with filters

Section titled “GET /api/v1/cve — list CVE records with filters”

Returns a paginated list of CVE records. At least one filter is required.

GET /api/v1/cve?vendor=Microsoft&severity=CRITICAL&has_exploit=true&limit=20&page=1

Query parameters

ParameterTypeDescription
vendorstringFilter by vendor name, case-insensitive
severitystringCRITICAL, HIGH, MEDIUM, LOW, NONE
cvss_minfloatMinimum CVSS score (0.0–10.0)
cvss_maxfloatMaximum CVSS score
epss_minfloatMinimum EPSS score (0.0–1.0). 0.05 means ≥5% probability of exploitation
has_exploitbooltrue — only CVEs with a public exploit or Nuclei template
has_patchbooltrue — only CVEs with a known patch
cisa_kevbooltrue — only CISA KEV entries
cwe_idstringFilter by CWE — e.g. CWE-89 for SQL injection
changed_sincedateISO 8601 — CVEs updated after this date
published_sincedateISO 8601 — CVEs published after this date
limitintResults per page, max 100 (default 20)
pageintPage number, 1-based (default 1)

Example: actively exploited critical vulnerabilities in the last 7 days

Terminal window
curl -s "https://api.valtersit.com/api/v1/cve" \
-H "Authorization: Bearer $VALTERSIT_API_KEY" \
-G \
--data-urlencode "severity=CRITICAL" \
--data-urlencode "has_exploit=true" \
--data-urlencode "published_since=$(date -d '7 days ago' +%Y-%m-%d)" \
--data-urlencode "limit=50" | jq '.data[] | {cve_id, cvss, epss, cisa_kev, poc_status}'
from datetime import date, timedelta
records = get("/cve", {
"severity": "CRITICAL",
"has_exploit": "true",
"published_since": (date.today() - timedelta(days=7)).isoformat(),
"limit": 50,
})
for r in records["data"]:
print(f"{r['cve_id']} CVSS {r['cvss']} EPSS {r['epss']:.4f} KEV: {r['cisa_kev']}")

Example: high-EPSS CVEs for a specific vendor

Terminal window
curl -s "https://api.valtersit.com/api/v1/cve" \
-H "Authorization: Bearer $VALTERSIT_API_KEY" \
-G \
--data-urlencode "vendor=Cisco" \
--data-urlencode "epss_min=0.1" \
--data-urlencode "limit=100" | jq '.data[] | {cve_id, cvss, epss, affected_version}'

Example: SQL injection CVEs with public exploits

Terminal window
curl -s "https://api.valtersit.com/api/v1/cve" \
-H "Authorization: Bearer $VALTERSIT_API_KEY" \
-G \
--data-urlencode "cwe_id=CWE-89" \
--data-urlencode "has_exploit=true" \
--data-urlencode "limit=50"

GET /api/v1/cve/{id} — single CVE record

Section titled “GET /api/v1/cve/{id} — single CVE record”
GET /api/v1/cve/CVE-2024-44000

Returns the full record for one CVE. This is the primary lookup for enriching alerts, tickets and patch notes.

Response fields

FieldTypeNotes
cve_idstringCVE-YYYY-NNNNN format
vendorstringAffected vendor/project
cvss_scorefloat0.0–10.0. Null while NVD is still scoring (typically 2–14 days from publication)
cvss_vectorstringCVSS:3.1/AV:N/AC:L/… format. Null while pending
severitystringCRITICAL / HIGH / MEDIUM / LOW / NONE
epssfloatProbability of exploitation in next 30 days, 0.0–1.0. 0.0031 = 0.31%. Updated daily by FIRST.org
cisa_kevbooltrue if in CISA Known Exploited Vulnerabilities catalogue
cwe_idstringe.g. CWE-89 (SQL injection)
mitre_tacticstringATT&CK technique, e.g. T1190 (Exploit Public-Facing Application)
affected_versionstringVersion strings from NVD CPE + CNA data
patch_statusstringPATCHED / FIX AVAILABLE · PATCH UNDER REVIEW · UNKNOWN / UNPATCHED
patch_detailsstringSpecific patch/version guidance
poc_statusstringPublic — a known PoC exists. None — no known public PoC
poc_urlstringURL to PoC or exploit reference
has_exploitbooltrue if poc_status=Public or a Nuclei template exists
has_patchbooltrue if patch_status is confirmed patched
nuclei_templatestringProjectDiscovery Nuclei template ID if one exists
shodan_dorksarrayShodan search strings for exposed instances
logo_base64stringVendor logo as data:image/png;base64,…
websitestringVendor’s official website
origin_countrystringVendor’s country of origin
publish_datedateNVD publication date
pending_fieldsarrayFields NVD has not yet filled in
backfilled_fieldsarrayFields filled in by ValtersIT after NVD publication
yara_rulestringYARA detection rule — Standard+ plan only, where a rule exists
wazuh_rulestringWazuh/OSSEC XML rule — Standard+ plan only
elastic_rulestringElastic SIEM detection rule — Standard+ plan only
sigma_rulestringSigma rule in YAML — Pro only
poc_codestringRaw proof-of-concept code — Pro only, where legally permissible

Example: full record lookup

Terminal window
curl -s "https://api.valtersit.com/api/v1/cve/CVE-2024-44000" \
-H "Authorization: Bearer $VALTERSIT_API_KEY" | jq '{
cve_id, vendor, cvss_score, cvss_vector,
epss, cisa_kev, poc_status,
affected_version, patch_status,
shodan_dorks, nuclei_template
}'
record = get("/cve/CVE-2024-44000")
# Triage logic
kev = record.get("cisa_kev", False)
epss = record.get("epss", 0) or 0
cvss = record.get("cvss_score", 0) or 0
exploit = record.get("has_exploit", False)
priority = "P1" if kev or epss > 0.3 else \
"P2" if cvss >= 9.0 or exploit else \
"P3" if cvss >= 7.0 else "P4"
print(f"{record['cve_id']} {priority} "
f"CVSS {cvss} EPSS {epss:.4f} KEV: {kev} Exploit: {exploit}")

Returns threat intelligence for one IP address. Requires Standard plan or above.

GET /api/v1/ip/203.0.113.5

Response fields

FieldTypeNotes
ipstringIPv4 or IPv6 address
threat_typestringscanner · malware_dist · botnet_c2 · phishing · tor · exploit_host · c2_server · spam · brute_force · mixed
confidenceint0–100. Conservative scoring — few IPs reach 75+. Start with min_confidence=50 for practical filtering
sourcesarrayData source names
cve_idsarrayCVEs this IP has been observed exploiting
malware_familiesarrayMalware families associated with this IP
country_codestringISO country code
asnstringAutonomous system number
orgstringAS organisation name
portsarrayObserved open ports
is_torboolKnown Tor exit node
is_vpnboolKnown VPN exit IP
last_seendatetimeLast observed activity
result = get(f"/ip/203.0.113.5")
if result.get("threat_type") and result.get("confidence", 0) >= 50:
print(f"Block {result['ip']}: {result['threat_type']} "
f"(confidence {result['confidence']}, seen {result['last_seen']})")

GET /api/v1/ip/feed — bulk threat IP feed

Section titled “GET /api/v1/ip/feed — bulk threat IP feed”

Returns the full threat-IP dataset for firewall import. Requires Standard plan or above. Standard plan: 500 rows per request. Pro plan: 1000 rows per request.

GET /api/v1/ip/feed?threat_type=botnet_c2&min_confidence=60

Query parameters

ParameterTypeDescription
threat_typestringOne of the type strings above
min_confidenceintMinimum confidence score (0–100)
pageintPage for pagination (1-based)

This endpoint is what the Threat-IP Blocklist Importer calls to render nftables, ipset, fail2ban, pfSense and MikroTik rulesets. Use it directly if you need a custom integration.

all_ips = []
page = 1
while True:
batch = get("/ip/feed", {"min_confidence": 50, "page": page})
ips = batch.get("data") or batch.get("ips") or []
if not ips:
break
all_ips.extend(ips)
if len(ips) < 500: # or 1000 on Pro
break
page += 1
print(f"Feed: {len(all_ips)} IPs")

POST /api/v1/scan — submit a component inventory for CVE matching

Section titled “POST /api/v1/scan — submit a component inventory for CVE matching”

Accepts a component list and a fingerprint, returns matched CVEs. This is the endpoint the open-source scanner suite calls after collecting the local component inventory.

POST /api/v1/scan
{
"fingerprint": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"components": [
{"vendor": "openssl", "product": "openssl", "version": "3.0.13"},
{"vendor": "wordpress", "product": "akismet", "version": "5.3.3"}
]
}

Fields

FieldTypeDescription
fingerprintstringSystem identifier ≥16 chars. The scanner generates a random 32-hex token stored in ~/.valtersit/fingerprint — it is never derived from your IP/hostname/MAC
componentsarrayArray of {vendor, product, version} objects. vendor and product are required

Response

{
"matched_cves": 1,
"results": [
{
"slug": "openssl",
"version": "3.0.13-0ubuntu3.4",
"cve_id": "CVE-2026-11023",
"cvss": 7.5,
"patched_in": "3.0.13-0ubuntu3.6"
}
]
}

All list endpoints (/cve, /ip/feed) support limit and page. When you need more records than one page returns, iterate:

def paginate(path, params, max_pages=100):
params = dict(params)
for page in range(1, max_pages + 1):
params["page"] = page
batch = get(path, params)
records = batch.get("data", [])
yield from records
if len(records) < params.get("limit", 20):
break
# All critical CVEs for Cisco, up to 500
for cve in paginate("/cve", {"vendor": "Cisco", "severity": "CRITICAL", "limit": 100}):
print(cve["cve_id"], cve.get("cvss_score"), cve.get("epss"))

Response field guide: CVSS, EPSS, CISA KEV

Section titled “Response field guide: CVSS, EPSS, CISA KEV”

CVSS score and vector

The CVSS score (cvss_score) ranges from 0.0 to 10.0. The vector string (cvss_vector) encodes the metric breakdown, e.g. CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. Parse it to prioritise:

def parse_cvss_vector(vector):
"""Returns a dict of CVSS metrics from a CVSS:3.1/... string."""
if not vector or not vector.startswith("CVSS:"):
return {}
parts = vector.split("/")[1:] # drop the 'CVSS:3.1' prefix
return dict(p.split(":") for p in parts if ":" in p)
v = parse_cvss_vector("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H")
# network-accessible, low complexity, no privileges, no user interaction → auto-exploitable
is_trivial = v.get("AV") == "N" and v.get("AC") == "L" and \
v.get("PR") == "N" and v.get("UI") == "N"

NVD typically assigns CVSS scores 2–14 days after publication. During that window, cvss_score is null and pending_fields will include "cvss_score". Plan for null in your code.

EPSS

EPSS (Exploit Prediction Scoring System) is the probability that a CVE will be exploited in the wild within the next 30 days, as scored by FIRST.org’s model. It is returned as a decimal float: 0.0031 means 0.31% probability. It is updated daily.

# Practical thresholds
def epss_tier(score):
if score is None: return "UNKNOWN"
if score >= 0.5: return "CRITICAL — actively exploited ecosystem"
if score >= 0.1: return "HIGH — significant exploitation activity"
if score >= 0.01: return "MEDIUM — some exploitation in the wild"
return "LOW — rare exploitation, mostly theoretical"

CISA KEV

cisa_kev: true means the CVE is in CISA’s Known Exploited Vulnerabilities catalogue — confirmed exploitation in a real attack. Treat any KEV entry as P1 regardless of CVSS. Federal agencies in the US are required to patch KEV entries within a defined remediation window; many private-sector teams use the same criterion.


Daily brief: new KEV entries

Terminal window
curl -s "https://api.valtersit.com/api/v1/cve" \
-H "Authorization: Bearer $VALTERSIT_API_KEY" \
-G \
--data-urlencode "cisa_kev=true" \
--data-urlencode "changed_since=$(date -d 'yesterday' +%Y-%m-%d)" \
--data-urlencode "limit=100" | jq '.data[] | {cve_id, vendor, cvss_score, epss}'

Watchlist alert: has a vendor’s CVE gained an exploit?

import json, urllib.request
WATCH_VENDORS = ["Palo Alto Networks", "Fortinet", "Cisco", "Ivanti"]
for vendor in WATCH_VENDORS:
results = get("/cve", {
"vendor": vendor,
"has_exploit": "true",
"changed_since": "2026-09-24",
"limit": 50,
})
for r in results.get("data", []):
print(f"[EXPLOIT ADDED] {r['cve_id']} {vendor} CVSS {r['cvss_score']} "
f"EPSS {(r['epss'] or 0):.4f}")

Enrich a SIEM alert with one call

def enrich_cve(cve_id: str) -> dict:
"""Returns triage fields for a CVE alert. Safe for missing or None values."""
try:
r = get(f"/cve/{cve_id}")
except Exception:
return {"cve_id": cve_id, "error": True}
return {
"cve_id": r.get("cve_id"),
"severity": r.get("severity"),
"cvss": r.get("cvss_score"),
"epss": r.get("epss"),
"cisa_kev": r.get("cisa_kev"),
"has_exploit": r.get("has_exploit"),
"nuclei": bool(r.get("nuclei_template")),
"patch_status": r.get("patch_status"),
"patched_in": r.get("patch_details"),
"shodan_dorks": r.get("shodan_dorks", []),
}
# In a Wazuh/Elastic alert handler:
fields = enrich_cve("CVE-2024-44000")
priority = "P1" if fields.get("cisa_kev") or (fields.get("epss") or 0) > 0.3 else "P2"

Gate a CI/CD build on newly published CVEs for your stack

#!/usr/bin/env bash
# ci-cve-gate.sh — exit 1 if new critical exploitable CVEs appeared since yesterday
SINCE=$(date -d 'yesterday' +%Y-%m-%d)
COUNT=$(curl -s "https://api.valtersit.com/api/v1/cve" \
-H "Authorization: Bearer $VALTERSIT_API_KEY" \
-G \
--data-urlencode "severity=CRITICAL" \
--data-urlencode "has_exploit=true" \
--data-urlencode "vendor=nginx" \
--data-urlencode "published_since=$SINCE" \
--data-urlencode "limit=1" | jq '.total // .count // 0')
if [ "$COUNT" -gt 0 ]; then
echo "::error::$COUNT new critical exploitable CVE(s) for nginx since $SINCE. Review before merging."
exit 1
fi
echo "CVE gate: no new critical exploits since $SINCE."

Build a YARA-based detection set (Standard plan)

yara_rules = []
for cve in paginate("/cve", {"has_exploit": "true", "epss_min": "0.1", "limit": 100}):
rule = cve.get("yara_rule")
if rule:
yara_rules.append(rule)
with open("valtersit_threat_rules.yar", "w") as f:
f.write("\n\n".join(yara_rules))
print(f"Wrote {len(yara_rules)} YARA rules")

PAYGStandardPro
Price€0.08/credit€19/mo founding (€29 reg)€65/mo founding (€99 reg)
CVE API✓ per credit✓ unlimited✓ unlimited
Threat-IP API✓ per credit✓✓
YARA / Wazuh / Elastic rules—✓✓
Sigma rules——✓
PoC code——✓
IP feed rows/request5005001000
Scanner system slotspay-as-you-go1 included5 included

Founding price locked for life while the subscription stays active. Offer ends 31 Dec 2026.

PAYG works without a subscription: buy credits, each API request costs one credit. Standard and Pro are monthly subscriptions with unlimited API requests plus the scanner slots above.

See full pricing and sign up →


import urllib.error
def safe_get(path, params=None):
try:
return get(path, params)
except urllib.error.HTTPError as e:
body = json.loads(e.read())
if e.code == 401:
raise SystemExit("Invalid API key — check VALTERSIT_API_KEY")
if e.code == 403:
raise SystemExit(f"Plan limit: {body.get('message')}")
if e.code == 429:
import time; time.sleep(60); return safe_get(path, params)
if e.code == 422:
raise ValueError(f"Invalid request: {body}")
raise
except urllib.error.URLError as e:
# Network or DNS failure — log and continue
print(f"Network error on {path}: {e}")
return None

Common HTTP responses:

  • 200 — success
  • 400 — missing required filter (list endpoints need at least one filter)
  • 401 — invalid or missing Authorization header
  • 403 — plan restriction (e.g. accessing /ip/feed without Standard+ plan)
  • 404 — CVE ID not in the database
  • 422 — validation error (malformed POST /scan body, invalid filter values)
  • 429 — rate limit exceeded — back off and retry

The key vit_sandbox_free_demo_key_2026 returns fixed demo data on CVE endpoints and allows you to test authentication and response parsing without a paid account. It returns 403 on /ip/feed, /ip/{ip}, and POST /scan with a clear “register for a real key” message.

Terminal window
# Test CVE lookup with sandbox key
curl -s "https://api.valtersit.com/api/v1/cve/CVE-2024-44000" \
-H "Authorization: Bearer vit_sandbox_free_demo_key_2026" | jq .

Use this to build and test your integration before subscribing. The demo response shape is identical to the live API shape.