Layers
Every text file is scanned by two independent extraction layers, run in parallel:
- Layer 1 — Regex
- Fast plain-text scan: URLs with a scheme (
http, https, ftp, ws, wss), IPv4 addresses appearing in networking calls (connect, urlopen, requests…), and full/compressed IPv6. Private and loopback IPs are filtered out automatically.
- Layer 2 — AST
- Static resolution of obfuscated URLs by walking the Python syntax tree: constant folding of string literals, binary-operator concatenation (
"http://" + "evil.com"), base64.b64decode(...) calls, f-strings with resolvable parts, and scope tracking of variables assigned earlier in the same function.
Results
What each column and badge in the table means:
- Tags column
- Three stacked values per finding — layer (
regex or ast, which layer produced it), method (how the URL was written in source: via_base64, via_concat, via_fstring, via_scope, raw_ip, or blank for a plain literal string), and threat (highlighted in red when set — see Threats below).
- Verdict badge
- A package is flagged suspicious once any finding's threat value is set (shortener, tunneling, exfiltration, ip_recon, malware_hosting, suspicious_tld, or punycode); otherwise it's clean. A bare IP address alone (
raw_ip, shown as method) doesn't count toward this verdict.
- HTTP status badge
- From
--check-http: the final status code after following redirects — green for 2xx, amber for 3xx, red for 4xx/5xx.
- Page title
- The page's
<title>, shown in italics, captured by --check-http when the request got a response.
- Certificate badge
- From
--check-ssl: LE flags a Let's Encrypt-issued certificate (free, instant issuance makes it a common choice for throwaway malicious infrastructure); any other issuer is shown as plain text.
Threats
Domain categories evaluated, in order, once a URL survives deduplication. raw_ip is shown as the method value in the Tags column rather than as a threat, and doesn't count toward the suspicious verdict above — the rest do:
| Category | Meaning | Examples |
raw_ip | Direct public IP address instead of a domain name | 185.220.101.x |
shortener | URL shortener that hides the real destination | bit.ly, tinyurl.com, t.co |
tunneling | Tunnel/exposure service for a local server | ngrok.io, workers.dev, serveo.net |
exfiltration | Known data-exfiltration destination | discord.com, t.me, pastebin.com, webhook.site |
ip_recon | Public-IP lookup service (network reconnaissance) | ipinfo.io, ifconfig.me, api.ipify.org |
malware_hosting | Anonymous file-hosting service | files.catbox.moe, gofile.io |
suspicious_tld | High-risk top-level domain | .tk, .ml, .zip, .xyz, .pw |
punycode | IDN label encoding a lookalike/homograph of a trusted brand | xn--pypl-4ve.com |
Binaries
From --check-binaries: every package is scanned for native executables/libraries (.exe, .dll, .pyd, .so, .dylib, .a, .o), each hashed and format-identified with LIEF. This is a separate table from the URL findings above, shown under the Binaries tab.
- Format column
PE (Windows), Mach-O (macOS) or ELF (Linux), detected from the file's own header — not from its extension. Files LIEF can't parse are unknown.
- SHA256 column
- Hash of the file's raw contents, truncated for display. The copy button copies the full hash; the VT link opens the hash's VirusTotal report.
- Signed badge
- signed or unsigned when determined; unknown when the format has no signature to check (always the case for ELF, which has no code-signing mechanism) or the file couldn't be parsed.
- Signer column
- The certificate subject for a genuinely signed PE (Authenticode) or Mach-O (CMS) binary. Mach-O binaries signed without a real certificate — common for locally compiled code — show as
ad-hoc, distinct from a real signer and from unsigned.
Install Hooks
From --check-install-hooks: every setup.py (at any depth) and every __init__.py in the package is scanned for calls into process-execution or network functions — code that runs at pip install time (including custom cmdclass overrides) or on first import. This is a separate table from the URL findings above, shown under the Install Hooks tab.
- Call column
- Qualified name of the flagged function, e.g.
subprocess.Popen — one of subprocess.*, os.system/popen/exec*/spawn*, socket.*, urllib.request.*, http.client.*, requests.*.
- Command column
- The full call expression as written in source, arguments included — e.g.
subprocess.Popen(['curl', url], shell=True). Shown as-is; obfuscated arguments (base64, etc.) are not decoded here.
- Context column
- Dotted enclosing scope —
module at top level, or a class/method path such as PostInstall.run when the call sits inside a custom cmdclass.
- Source column
setup.py or __init__.py — which file the call was found in.