depsentinel 🛡️
Supply chain attack scanner for PyPI packages.
Most vulnerability scanners only check against known CVE databases — reactive by nature. depsentinel catches what they miss: malicious install hooks, obfuscated payloads, data exfiltration, CPU bombs, and dependency confusion attacks, before the package ever runs on your system.
Install
pip install depsentinel
Usage
# Drop-in replacement for pip install
depsentinel pip install requests
depsentinel pip install numpy pandas
# View scan history
depsentinel audit
How It Works
Two phases run in sequence before any package is installed:
Phase 1 — Static Analysis
Downloads the package without installing it, then inspects:
- Typosquatting — Levenshtein distance check against the top 5000 PyPI packages (
requets,djano, etc.) - Provenance — package age, download count, missing source repository
- AST scan — parses every
.pyfile in the package for:exec()/eval()with dynamic arguments at module levelbase64.b64decode→execchains (obfuscated payloads)subprocess,os.system,os.popencalls- Network calls at module level (
requests.get,socket.connect, etc.) - Reads of sensitive files (
.ssh/,.aws/credentials,.m2/settings.xml) - Environment variable harvesting (
SECRET,TOKEN,API_KEY, etc.) - High-entropy string literals (encrypted/encoded payloads)
sys.pathmutation (path poisoning)
- Metadata anomalies — compiled binaries with no source, git URLs in dependencies
Phase 2 — Dynamic Sandbox
Imports the package inside an isolated subprocess with:
- CPU time limit (10s hard cap via
RLIMIT_CPU) - Memory cap (512MB via
RLIMIT_AS) - Process limit (no fork bombs via
RLIMIT_NPROC) - Network fully blocked (socket.connect patched)
- Subprocess execution blocked
- Sensitive file reads intercepted
Reports on:
- Import time (infinite loop / CPU bomb detection)
- Background threads spawned on import (crypto miners, C2 beacons)
- Network connection attempts
- Subprocess execution attempts
- Sensitive file access attempts
- Memory growth on import (OOM bomb detection)
Output
────────────────────────────────────────────────────
Scanning: requets
→ requets v0.0.1
[STATIC]
✗ Likely typosquat of 'requests' (edit distance 1)
✗ Published 2 days ago
✗ Very low downloads: 14/month
✗ setup.py calls subprocess.run at module level
✗ base64 import + exec() = obfuscated payload pattern
🚫 Risk: CRITICAL
🚫 Install blocked: requets
────────────────────────────────────────────────────
Scanning: requests
→ requests v2.33.1
[STATIC]
✓ Risk: LOW
[DYNAMIC]
✓ Import time OK (0.509s)
✓ No unexpected threads spawned
✓ No network attempts detected
✓ No subprocess calls detected
✓ No sensitive file access detected
✓ Memory growth OK (+0MB)
✓ Risk: OK
✓ All packages passed. Proceeding with install...
Risk Levels
| Level | Action |
|---|---|
| OK / LOW | Proceeds automatically |
| MEDIUM | Proceeds with warning logged to audit |
| HIGH | Prompts for confirmation before Phase 2 |
| CRITICAL | Hard block — install does not proceed |
Audit Log
Every scan is appended to ~/.depsentinel_audit.jsonl:
depsentinel audit
# 2025-04-13T10:22:01 LOW requests
# 2025-04-13T10:23:44 CRITICAL requets
Attack Types Detected
| Attack | Static | Dynamic |
|---|---|---|
| Malicious install hooks | ✅ | ✅ |
| Obfuscated payload (base64+exec) | ✅ | ✅ |
| Credential harvesting | ✅ | ✅ |
| Network exfiltration | ✅ | ✅ |
| Typosquatting | ✅ | — |
| Dependency confusion | ✅ | — |
| CPU bomb / infinite loop | ⚠️ partial | ✅ |
| OOM bomb | ❌ | ✅ |
| Thread spawning (miner/C2) | ❌ | ✅ |
| Fork bomb | ❌ | ✅ |
| Monkey patching | ⚠️ partial | ✅ |
Limitations
- Dynamic sandbox uses
setrlimit— full isolation requires Linux (unshare --net). On macOS/Windows, network blocking is applied via socket patching only. - Transitive dependency scanning (sub-deps) is on the roadmap.
- Maven/Gradle support coming soon.
License
MIT
Release files for depsentinel 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| depsentinel-0.1.1.tar.gz | 12.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| depsentinel-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 26.0 kB
Release files / depsentinel-0.1.1.tar.gz
| Download URL | depsentinel-0.1.1.tar.gz |
|---|---|
| Size | 12.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cbe71640a651ac66a1608976a14378ea081ee585dc4540d843f113ec16974e9f
|
|
BLAKE2b-256 checksum How to use checksums |
769cd9a6fadf1349a1487997c4c985259a3405bdd77775d18dfedd1c07189902
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / depsentinel-0.1.1-py3-none-any.whl
| Download URL | depsentinel-0.1.1-py3-none-any.whl |
|---|---|
| Size | 14.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5aed866508c3b8a720921eabea8b735b768e2f9a748f3272a1c7895fa11a5aaa
|
|
BLAKE2b-256 checksum How to use checksums |
1f61b82f60c9fc0b2cb1c10a52f42c341aa5c041f1421dd73ee9ec0ef230614c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|