VirusTotal to ThreatQ (ThreatQuotient) Integration
Enrich existing ThreatQ indicators with VirusTotal verdicts so analysts have multi-engine context inline with the indicator record. The integration walks a watchlist of ThreatQ indicators (or all updated-since indicators), looks each one up in VirusTotal API v3, and writes the analysis back as an attribute on the indicator.
This is an enrichment pattern, not a one-way feed: the target indicator already exists in ThreatQ. The integration's job is to add context, not to create new indicators from VT.
What you get
A real excerpt from a generated VirusTotal-to-ThreatQ (ThreatQuotient) integration. The full script ships with logging, env-var loading, error handling, FIFO-capped dedup state, and a README.
# RINOX INTEGRATION: VirusTotal -> ThreatQ enrichment
def lookup_vt(hash_value):
# API v3 — single call returns analysis stats AND per-engine results.
resp = requests.get(f"https://www.virustotal.com/api/v3/files/{hash_value}",
headers={"x-apikey": VT_KEY}, timeout=20)
if resp.status_code == 404:
return None
resp.raise_for_status()
return resp.json()["data"]["attributes"]
def map_severity(stats):
malicious = stats.get("malicious", 0)
suspicious = stats.get("suspicious", 0)
if malicious >= 5: return "high"
if malicious >= 1 or suspicious >= 3: return "medium"
return "low"Common pitfalls
The mistakes that turn this integration from "works once" into "loses data silently for three weeks."
- 01VT API v3 returns nested `data.attributes.last_analysis_stats` and `data.attributes.last_analysis_results`. Extract from the bulk lookup payload, do not make a separate call per engine (N+1 elimination, Phase 3).
- 02VT free tier rate-limits at 4 requests/minute, 500/day. Honour `X-RateLimit-Remaining` and back off rather than hammering the API.
- 03ThreatQ's attribute API requires the indicator type as part of the path. Pre-resolve indicator type from the ThreatQ payload, do not re-query.
- 04Map VT severity to ThreatQ score with an explicit table — do not silently coerce `harmless` and `undetected` into the same bucket as the type-safety appendix calls out.
Generate this for your environment.
Pre-fills the form with VirusTotal and ThreatQ (ThreatQuotient). You write a sentence about your use case, we write the rest.
Generate VirusTotal → ThreatQ (ThreatQuotient)Frequently asked
Does this overwrite existing ThreatQ attributes?
No — it appends. The generated script writes attributes with a `source: virustotal` tag so subsequent runs can update or replace them deterministically.
What if I have a VT private API key?
Same path. Private keys give you higher rate limits and additional fields, and the generated script honours `VT_PRIVATE_KEY=true` by enabling the extra fields.
Can I run this on URL or domain indicators too?
Yes — the script dispatches by indicator type. Hashes hit `/files/{id}`, URLs hit `/urls/{id}`, domains hit `/domains/{name}`.
How does it avoid hammering ThreatQ?
Batched indicator pull at the top, per-indicator VT lookup with rate-aware backoff, batched ThreatQ writes at the bottom. One round-trip in, one round-trip out per indicator.