Skip to main content

Sentro — scan Python packages for malicious code, typosquatting & supply-chain attacks before install. Docs: sentro-docs.onrender.com

Project description

sentro

PyPI Python License: MIT Docs

Scan Python packages for malicious code, typosquatting, and supply-chain attacks — before they ever install.

Built by Solvyx.dev

sentro install requests
╭──────────────────────── sentro scan ─────────────────────────╮
│   Package : requests 2.31.0                                     │
│   PyPI    : verified                                            │
│   Risk    : SAFE  (score 0/100)                                 │
╰─────────────────────────────────────────────────────────────────╯
  No issues found.

What it detects

  • Malicious codeeval() / exec() at module level, os.system(), socket connections to hardcoded IPs
  • Install hooks — dangerous calls in setup.py that run unconditionally at install time
  • Obfuscationexec(base64.b64decode(...)) chains, high-entropy strings, marshal.loads payloads
  • Typosquatting — names similar to popular packages (reqeusts, numpy-dev), Unicode homoglyphs
  • Dependency confusion — package names that shadow Python stdlib modules
  • Metadata signals — very new packages, suspiciously low download counts, missing author info

Each finding contributes to a risk score (0–100). The overall verdict is SAFE, WARNING, or DANGER.


Install

pip install sentro

Requires Python 3.11+.


Quick start

# Scan and install
sentro install requests

# Scan only — don't install
sentro install requests --no-install

# Block install if anything scores DANGER (for CI pipelines)
sentro install requests --strict

Full documentation — configuration reference, all CLI flags, CI integration guide, installer detection, and more:

sentro-docs.onrender.com


License

MIT — built and maintained by Solvyx.dev

Sentro Documentation

Scan Python packages for malicious code, typosquatting, and supply-chain attacks — before they ever install.

Sentro acts as a security-aware wrapper around pip, uv, poetry, and other Python package managers. It downloads the package from PyPI, statically analyzes the source code, and gives you a risk verdict (SAFE, WARNING, or DANGER) — all before a single byte of malicious code touches your environment.


Table of Contents

  1. Install
  2. Quick Start
  3. CLI Reference
  4. Configuration
  5. What Sentro Detects
  6. Reputation-Aware Scoring
  7. Output Formats
  8. CI Integration
  9. Troubleshooting False Positives

Install

pip install sentro

Requires Python 3.11+.


Quick Start

# Scan and install
sentro install requests

# Scan only — do not install
sentro install requests --no-install

# Block installation if DANGER is detected (great for CI)
sentro install requests --strict

# Detailed output with per-scanner summaries and metadata
sentro install requests --verbose

CLI Reference

sentro install <packages...>

The main command. Scans each package, prints a report, then forwards to the detected package manager (pip by default, or uv/poetry/etc. when available).

Flag Env Var Description
--strict SENTRO_STRICT=1 Exit with error and block installation if any package scores DANGER.
--no-install Scan only; do not invoke the installer.
--skip-scan Skip scanning entirely and pass straight to the installer.
-v, --verbose SENTRO_VERBOSE=1 Show detailed findings, per-scanner summaries, package age, download counts, and progress messages.
--output-format {text,json} SENTRO_OUTPUT_FORMAT Change report format. JSON supports verbose metadata.
--installer {pip,uv,conda,mamba,poetry,pipenv,pdm,auto} SENTRO_INSTALLER Force a specific installer. Default is auto.
-r requirements.txt Scan all packages listed in a requirements file.
--config path.toml Load an explicit TOML config file.

All unknown flags (e.g. --index-url, --constraint) are forwarded transparently to the underlying installer.

sentro detect-installer

Shows which package manager Sentro would use automatically.

$ sentro detect-installer
Detected installer: uv

Configuration

Sentro merges configuration from multiple sources (lowest to highest priority):

  1. Built-in defaults
  2. ~/.config/sentro/config.toml
  3. pyproject.toml[tool.sentro]
  4. .sentro.toml in the current directory
  5. Explicit --config path
  6. SENTRO_* environment variables
  7. CLI flags

Example .sentro.toml

[sentro]
strict = false
verbose = false
output_format = "text"
whitelist_packages = ["my-internal-lib", "another-private-pkg"]
scanners_disabled = ["metadata"]
pypi_timeout = 15
prefer_wheel = true

[sentro.thresholds]
warning = 30
danger = 70

Environment Variables

Variable Effect
SENTRO_STRICT=1 Enable strict mode
SENTRO_VERBOSE=1 Enable verbose output
SENTRO_OUTPUT_FORMAT=json Set output format
SENTRO_DANGER_THRESHOLD=70 Override danger threshold
SENTRO_WARNING_THRESHOLD=30 Override warning threshold
SENTRO_WHITELIST=pkg1,pkg2 Comma-separated whitelist

What Sentro Detects

Sentro runs multiple specialized scanners against every package. Findings are aggregated into a single risk score (0–100).

1. Malicious Code (malicious_code)

Detects dynamic code execution, shell invocations, network anomalies, and real-world malware patterns.

Pattern Severity Notes
eval() / exec() at module level DANGER Runs unconditionally on import.
eval(base64.b64decode(...)) / exec(zlib.decompress(...)) DANGER Classic obfuscation chain.
os.system(...) DANGER or INFO Downgraded to INFO in CLI / viewer / launcher contexts.
subprocess(..., shell=True) DANGER or WARNING Downgraded for known-safe commands (git log, xdg-open, clear, etc.).
socket.connect(("1.2.3.4", port)) DANGER Hardcoded IPs are strong C2 indicators.
socket.connect(("8.8.8.8", port)) INFO (score 0) Recognized as the common local-IP detection trick.
requests.get("https://pastebin.com/...") WARNING Pastebin, Discord webhooks, Telegram, raw GitHub, and similar staging services.
open("~/.bashrc", "a") DANGER Writing to sensitive files (persistence / credential theft).
ctypes.CDLL("./payload.so") WARNING Loading native libraries — common payload hiding technique.
getattr(__builtins__, "eval") DANGER Reflection evasion used to bypass simple static analysis.
pip.main(["install", "evil"]) DANGER Programmatic pip installs (chain-loading malware).
subprocess.run([sys.executable, "-m", "pip", "install", ...]) DANGER Same as above, via subprocess.
importlib.import_module(variable) WARNING Dynamic imports outside try/except blocks. Skipped for normal compatibility shims.

Smart exclusions:

  • # nosec comments suppress findings on that line (Bandit convention).
  • Name-shadowed builtins (e.g. from mylib import eval) are ignored.
  • eval(compile(..., "exec")) — the standard file-loading pattern — is scored as INFO (5) instead of double-flagged.
  • compile() inside a function by itself is skipped entirely.
  • __import__() at module level is INFO (0) because it is overwhelmingly used for lazy loading.

2. Obfuscation (obfuscation)

Pattern Severity
exec(base64.b64decode(...)) chains DANGER
Large base64/hex string constants WARNING
High-entropy strings (>6.2 bits/char) WARNING — only when other suspicious findings already exist in the same file
marshal.loads chains DANGER

Test files are skipped for encoded-constant checks (they legitimately contain fixtures and key material).

3. Setup Hooks (setup_hooks)

Analyzes setup.py for dangerous install-time behavior.

Pattern Severity
os.system() / exec() / eval() at module scope in setup.py DANGER
cmdclass override WARNING
Dynamic install_requires WARNING

4. Typosquatting (typosquatting)

Pattern Severity
Non-ASCII / homoglyph characters in package name DANGER
Name very similar to a top PyPI package WARNING
Popular package + suspicious suffix (-dev, -fix, 2, 3) WARNING

5. Dependency Confusion (dependency_confusion)

Pattern Severity
Package shadows a Python stdlib module (json, os, urllib) DANGER
Package not found on PyPI DANGER

6. Metadata (metadata)

Uses PyPI API data to surface reputation signals.

Pattern Severity
Published < 7 days ago DANGER
Published < 30 days ago WARNING
< 100 downloads last month WARNING
Only one release ever WARNING
No author, homepage, or description WARNING

Reputation-Aware Scoring

Not every eval() call is malicious. Sentro uses package reputation to avoid false-positive WARNING / DANGER on established, heavily-downloaded libraries.

If a package has no DANGER findings, its raw score is multiplied by a reputation discount:

Downloads last month Age Discount Example effect
> 50,000 > 1 year 0.25× numpy, requests, pandas
> 10,000 > 90 days 0.5× flask, django
> 1,000 > 30 days 0.75× Mid-size utilities
≤ 1,000 or ≤ 30 days 1.0× (no discount) Brand-new / niche packages

Important: Discounts are ignored as soon as a single DANGER-severity finding exists (e.g. a decode-exec chain). Real malware always scores at full strength.

In --verbose mode you can see the exact discount applied:

Reputation discount  : 25%

Output Formats

Text (default)

Clean, colorized terminal output. Use -v for extra columns and a per-scanner summary table.

sentro install requests -v

JSON

Machine-readable output ideal for CI dashboards.

sentro install requests --output-format json -v

Verbose JSON adds:

  • metadataage_days, download_stats, reputation_discount
  • scanner_summary — count of findings per scanner by severity

CI Integration

Use --strict in CI pipelines to fail the build when malicious code is detected:

# .github/workflows/security.yml
- name: Scan dependencies with Sentro
  run: sentro install -r requirements.txt --strict

If any package scores DANGER, Sentro exits with code 1 and blocks installation.

For machine-readable CI logs, combine with JSON:

- run: sentro install -r requirements.txt --strict --output-format json -v

Troubleshooting False Positives

Sentro is designed to minimize false positives through contextual heuristics, but if you encounter one:

  1. Check --verbose to see exactly which scanner and rule triggered.
  2. Add # nosec to the line in your own code if the finding is intentional (Bandit convention).
  3. Whitelist internal packages in .sentro.toml:
    whitelist_packages = ["my-private-lib"]
    
  4. Disable a specific scanner if it is noisy for your use case:
    scanners_disabled = ["metadata"]
    

If a top PyPI package is still falsely flagged as DANGER, please open an issue — it is treated as a high-priority bug.


Changelog Highlights

Accuracy & False-Positive Reduction

  • Name-shadowing detection — locally imported eval / exec names are no longer confused with builtins.
  • Compile-exec deduplicationexec(compile(..., "exec")) is recognized as the standard file-loading pattern.
  • Per-file finding caps — repeated identical patterns in large packages (e.g. numpy f2py) are collapsed into a summary note.
  • Safe-command regexgit log, xdg-open, clear, make, --version in subprocess(shell=True) are downgraded.
  • Safe-public-IP detection8.8.8.8, 1.1.1.1, etc. used for local-IP discovery are scored as INFO (0).
  • # nosec support — suppresses findings on manually reviewed lines.

New Real-World Attack Detections

  • Sensitive file writes (~/.bashrc, ~/.ssh/authorized_keys, cron dirs, Windows startup)
  • Programmatic pip installations (pip.main, subprocess pip install)
  • ctypes native library loading
  • getattr(__builtins__, "eval") reflection evasion
  • Dynamic importlib.import_module (outside try/except)
  • Hardcoded requests to suspicious staging URLs (Pastebin, Discord, Telegram, raw GitHub)

Reporting & UX

  • --verbose / -v flag for detailed findings, progress messages, scanner summaries, and metadata.
  • Enhanced text report with age, downloads, reputation discount, and per-scanner breakdown.
  • Enhanced JSON report with metadata and scanner_summary in verbose mode.
  • Progress indicators during multi-package scans.

License: MIT — built and maintained by Solvyx.dev

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sentro-0.1.6.tar.gz (80.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sentro-0.1.6-py3-none-any.whl (47.1 kB view details)

Uploaded Python 3

File details

Details for the file sentro-0.1.6.tar.gz.

File metadata

  • Download URL: sentro-0.1.6.tar.gz
  • Upload date:
  • Size: 80.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for sentro-0.1.6.tar.gz
Algorithm Hash digest
SHA256 65e13f403fdd471364092555d4156549877aa71b554e9895615eb7f3b82d0d6d
MD5 9b66e17a81f95b31551f1114fe102a2f
BLAKE2b-256 a5dbca4d470639d5fda3410b34e21d7f3eaddf20ad64fba1f9dc5b2feac130ab

See more details on using hashes here.

File details

Details for the file sentro-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: sentro-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 47.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for sentro-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 9e0a4d43db118e58037b14b304f2db8893ba647ff95aa40663045814acb877b1
MD5 87cb1fbd75f524e1f04431346c5c8436
BLAKE2b-256 75322cd6ddf3a9fbc128736cea0137dad1d1b9dceee07ee9d27eb4573717fc1b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page