Skip to content

Checking links

blackhole check reads the URL as text and scores it. It never opens the page, never does DNS, never calls an API. Safe to run on the nastiest "free nitro" lure.

Quick start

blackhole check "http://secure.paypal.com.evil.tk/login"
MALICIOUS 68/100 (HIGH) hxxp[:]//secure[.]paypal[.]com[.]evil[.]tk/login
  +18 brand_impersonation: brand=paypal host=secure.paypal.com.evil.tk
  +10 suspicious_tld: .tk
  + 8 suspicious_keywords: login,secure

Notice the output is defanged (hxxp[://], [.]) so it can't be clicked by accident.

Scores

Range Verdict What I do
0-20 BENIGN Carry on
21-49 SUSPICIOUS Hover, verify sender, don't log in
50-100 MALICIOUS Don't touch it

Confidence (VERY_LOW → HIGH) is based on how many signals fired. Every signal prints its weight, the evidence, and a MITRE tag like T1566.002 so you can look it up.

Batch and scripts

# a list of links
blackhole check -f urls.txt --json > report.json

# from a pipe
echo "http://paypal-secure.tk/login" | blackhole check --file -

# CSV for a spreadsheet
blackhole check -f urls.txt --csv > report.csv

# fail the build on anything scary
blackhole check "http://evil.tk/x" --threshold 50; echo $?
# exit 2 means something scored at or above the threshold

What it looks at

Short version: IP hosts, punycode and homoglyphs, shorteners, odd TLDs, long URLs, deep paths, tons of subdomains or hyphens, @ tricks, missing https, weird ports, heavy percent-encoding, high entropy, lure words (login, nitro, wallet…), .exe-style paths, open-redirect params, brand names in the wrong domain, near-miss typos (paypa1), free-hosting domains, digit-heavy names, and embedded credentials.

Long version lives in src/blackhole_sec/check/features.py - it's one readable file, tweak the lists to taste.

Limits

Lexical only. It can't catch a hacked WordPress page on a legit domain, and brand-new lure words need adding by hand. That's the trade for never touching the network.