DEV Community

Alex Spinov
Alex Spinov

Posted on

VirusTotal Has a Free API — Scan Files, URLs, and Domains for Malware (4 Requests/Min)

The Security Tool Every Developer Should Know

VirusTotal scans files and URLs against 70+ antivirus engines simultaneously. Their free API gives you 4 requests per minute — enough for security automation in small projects.

Setup

import requests
import hashlib

API_KEY = "your_virustotal_api_key"  # Free at virustotal.com
BASE = "https://www.virustotal.com/api/v3"
HEADERS = {"x-apikey": API_KEY}
Enter fullscreen mode Exit fullscreen mode

Scan a URL

import base64

def scan_url(url):
    # Submit URL for scanning
    r = requests.post(f"{BASE}/urls", headers=HEADERS,
                      data={"url": url})

    # Get the URL ID
    url_id = base64.urlsafe_b64encode(url.encode()).decode().strip("=")

    # Get results
    r = requests.get(f"{BASE}/urls/{url_id}", headers=HEADERS)
    stats = r.json()["data"]["attributes"]["last_analysis_stats"]
    return {
        "malicious": stats["malicious"],
        "suspicious": stats["suspicious"],
        "harmless": stats["harmless"],
        "undetected": stats["undetected"]
    }

result = scan_url("https://example.com")
if result["malicious"] > 0:
    print(f"WARNING: {result[malicious]} engines flagged this URL!")
else:
    print("Clean")
Enter fullscreen mode Exit fullscreen mode

Scan a File by Hash

def check_file_hash(file_path):
    # Calculate SHA-256
    with open(file_path, "rb") as f:
        sha256 = hashlib.sha256(f.read()).hexdigest()

    # Check against VirusTotal
    r = requests.get(f"{BASE}/files/{sha256}", headers=HEADERS)
    if r.status_code == 200:
        stats = r.json()["data"]["attributes"]["last_analysis_stats"]
        return {"hash": sha256, **stats}
    return {"hash": sha256, "status": "not_found"}

result = check_file_hash("suspicious_file.exe")
print(f"Malicious: {result.get(malicious, 0)} engines")
Enter fullscreen mode Exit fullscreen mode

Check a Domain

def check_domain(domain):
    r = requests.get(f"{BASE}/domains/{domain}", headers=HEADERS)
    data = r.json()["data"]["attributes"]
    return {
        "reputation": data.get("reputation", 0),
        "malicious": data["last_analysis_stats"]["malicious"],
        "categories": data.get("categories", {}),
        "creation_date": data.get("creation_date")
    }

info = check_domain("google.com")
print(f"Reputation: {info[reputation]}")
print(f"Malicious detections: {info[malicious]}")
Enter fullscreen mode Exit fullscreen mode

Real Use Cases

  1. CI/CD pipeline — scan downloaded dependencies before deployment
  2. Email security — check attachments and links before opening
  3. Web app — validate user-uploaded files
  4. Incident response — quickly check IOCs against 70+ engines
  5. Phishing detection — verify suspicious URLs in real-time

Free vs Premium

Feature Free Premium
Lookups 4/min 1000/min
File upload 32MB 650MB
Hunting rules No Yes
Intelligence feeds No Yes
Commercial use Limited Yes

4 requests per minute is enough for manual checks and small automation scripts.


More security tutorials | GitHub


More from me: 10 Dev Tools I Use Daily | 77 Scrapers on a Schedule | 150+ Free APIs

Top comments (0)