Skip to main content

threatlens

Detect malicious URLs and Windows executables from Python
Calibrated ML models that ship inside the package — no API keys, no network calls at inference time.

PyPI Python versions License Models bundled


from threatlens import URLDetector

detector = URLDetector()
result = detector.predict("https://secure-paypal-login.xyz/verify-account")

print(result.verdict)      # 'malicious'
print(result.score)        # 0.99...
print(result.confidence)   # 99.9
print(result.signals)      # {'has_suspicious_tld': 1, 'phishing_keyword_count': 5, ...}

Install

pip install threatlens-ml              # URL detection
pip install "threatlens-ml[files]"     # + Windows executable (PE) detection

The PyPI package is threatlens-ml (the plain name was taken by an unrelated project), but you still import threatlens in code.

URL detection is the default and has light dependencies. Executable detection adds LIEF for binary parsing, so it lives behind the files extra.

Why another detector

Most lexical URL classifiers are trained on corpora that quietly label popular domains as malicious, so they "detect" github.com as a threat and score everything at a flat 100%. threatlens was rebuilt specifically to fix that:

  • the training corpus was decontaminated (mislabelled trusted-domain rows removed, verified benign URLs injected),
  • the stacked score is isotonically calibrated, so probabilities are honest instead of pinned to 0 or 1,
  • and a trusted-domain safety net dampens residual edge cases.

The result: github.com scores 0.4%, google.com 0.02%, and obvious phishing still scores ~100%.

What it does

URLs

A calibrated stacking ensemble scores a URL from 66 lexical features — length, entropy, character distribution, suspicious TLDs, brand-in-subdomain tricks, punycode homoglyphs, shorteners, and more:

             ┌─ XGBoost ────────┐
 66 features ┤                  │
             └─ LightGBM ───────┤
                                ├─→ Logistic Regression ─→ isotonic ─→ score
 raw URL text ─ TF-IDF + LR ────┘      meta-learner        calibration

The three base models each estimate P(malicious); a logistic meta-learner stacks them; isotonic regression calibrates the result into a usable probability.

Executables

Windows PE files (.exe / .dll / .sys) are parsed into 2381 EMBER 2018 v2 features via LIEF and scored by a gradient-boosted classifier.

from threatlens import PEDetector          # pip install "threatlens-ml[files]"

pe = PEDetector()
print(pe.predict_file("sample.exe"))        # BENIGN (2.1%, high confidence) — sample.exe

Command line

threatlens https://github.com https://secure-paypal-login.xyz/verify
threatlens suspicious.exe --json
threatlens https://example.com --threshold 0.3
$ threatlens https://github.com "https://appleid-verify.ml/signin"
BENIGN (0.4%, high confidence) — https://github.com
MALICIOUS (99.8%, high confidence) — https://appleid-verify.ml/signin

The exit code is 1 if anything was flagged malicious, 0 otherwise — convenient in CI and shell pipelines.

The result object

Every call returns a DetectionResult:

field meaning
target the URL, or the file path / sha256
kind "url" or "pe"
verdict "malicious" or "benign"
score calibrated probability of maliciousness, 0–1
confidence distance from the decision boundary, 0–99.9
signals notable feature values behind the verdict
details per-model scores, sha256, threshold, raw (pre-calibration) score
elapsed_ms inference time

Plus result.is_malicious, result.confidence_level ("high" / "medium" / "low"), and result.to_dict() for JSON serialization.

r = detector.predict("http://192.168.1.50/login.php?bank=chase")
if r.is_malicious and r.confidence_level == "high":
    block(r.target)

Batch scanning

The detector loads its models once at construction; reuse the instance across calls.

detector = URLDetector()
flagged = [u for u in urls if detector.predict(u).is_malicious]

Custom models

Point a detector at your own trained artifacts instead of the bundled ones:

URLDetector(models_dir="path/to/url_models")
PEDetector(model_path="path/to/xgb.joblib")

The URL directory must contain scaler, xgb_binary, lgbm_binary, tfidf_lr_binary, hypermodel_meta, and hypermodel_calibrator .joblib files; the meta-learner must take 3 inputs (the constructor verifies this and fails loudly on a mismatch).

You can also disable the trusted-domain safety net to see the raw model opinion:

URLDetector(use_trusted_domains=False)

Accuracy & honest limitations

model test set accuracy AUC
URL ensemble 240,000 held-out URLs 97.89% 0.998
PE classifier EMBER 2018 v2 test set 97.59% —

These are static / lexical detectors: they read structure and text, not runtime behaviour. Treat a verdict as a strong signal, not proof, and keep a human in the loop for consequential decisions. The trusted-domain list is a pragmatic backstop, not a substitute for judgement — a genuinely compromised page on a trusted domain will be under-scored.

Development

git clone https://github.com/HeshamXOR/threatlens
cd threatlens
pip install -e ".[dev]"
pytest

License & attribution

Apache-2.0. Extracted from the MalwareGuard project. PE feature extraction is ported from elastic/ember (MIT). Full attributions in NOTICE.

Metadata

Release files for threatlens-ml 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for threatlens-ml 0.1.0
File Size Uploaded
threatlens_ml-0.1.0.tar.gz 2.9 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for threatlens-ml 0.1.0
File Interpreter ABI Platform
threatlens_ml-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 5.8 MB

Release files / threatlens_ml-0.1.0.tar.gz

Download URL threatlens_ml-0.1.0.tar.gz
Size 2.9 MB
Tags Source
SHA-256 checksum
How to use checksums
a47cc33e8a41ae083eab1f6770fd455b3475d7e54da39b351bc3d19cc7305375
BLAKE2b-256 checksum
How to use checksums
f619752e353db450a2ea39578d6f51900c227fd6ff2471127a523a23906e0a9a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release files / threatlens_ml-0.1.0-py3-none-any.whl

Download URL threatlens_ml-0.1.0-py3-none-any.whl
Size 2.9 MB
Tags Python 3
SHA-256 checksum
How to use checksums
bcbdd8689b560aa72dcd0cf515e600608df6368457c159caf865a219366e69e2
BLAKE2b-256 checksum
How to use checksums
be07751eb81083ad4e3d7a7ce744c71c791774c5fc86b2e2ca2582f61e238e7a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page