
Multi-Ecosystem Malicious Package Detection and Supply Chain Security Scanner
Multi-Ecosystem Malicious Package Detection and Supply Chain Security Scanner
A production-grade security tool for detecting malicious packages and supply chain threats across npm, PyPI, Maven, RubyGems, Go, and Cargo ecosystems. Leverages automated threat intelligence collection from trusted security sources to identify compromised dependencies in your projects.
OreWatch is the product and PyPI package name. The current source repository path still uses ore-mal-pkg-inspector.
https://github.com/rapticore/ore-mal-pkg-inspector/issues/2#issue-4215016110
https://github.com/rapticore/ore-mal-pkg-inspector/issues/3#issue-4215017945
https://github.com/rapticore/ore-mal-pkg-inspector/issues/4#issue-4215019385
https://github.com/rapticore/ore-mal-pkg-inspector/issues/5#issue-4215021599
Supply chain attacks are now the primary threat vector for software compromise. In 2024 alone, thousands of malicious packages were published to npm, PyPI, and other package registries, targeting developers with typosquatting, dependency confusion, and sophisticated malware campaigns like Shai-Hulud.
The challenge: Organizations and developers need to:
The gap: Existing solutions are often:
OreWatch addresses these challenges by providing:
Comprehensive Multi-Ecosystem Coverage: Single tool for npm, PyPI, Maven, RubyGems, Go, and Cargo packages
Automated Threat Intelligence: Dynamically collects and merges data from trusted security research sources
Active IoC Detection: Identifies Shai-Hulud attack patterns and other malicious code indicators beyond package name matching
CI/CD Ready: Designed for seamless integration into GitHub Actions, GitLab CI, Jenkins, and other automation platforms
Open Source and Transparent: Complete visibility into detection logic, data sources, and scanning methodology
Multi-Ecosystem Support Scans npm, PyPI, Maven, RubyGems, Go, and Cargo packages with automatic ecosystem detection from project structure.
Unified Threat Intelligence Database Checks against dynamically collected malicious package databases from trusted security research sources.
Automatic Ecosystem Detection Intelligently identifies ecosystems from directory structure, file names, and can scan multiple ecosystems in a single run.
Indicators of Compromise (IoC) Detection Scans for Shai-Hulud attack patterns (original and 2.0 variants), malicious hooks, suspicious workflows, and known payload files.
Shai-Hulud Integration Cross-references npm packages against the comprehensive Shai-Hulud affected packages list from OreNPMGuard.
Structured JSON Reporting Generates machine-readable JSON reports with explicit threat-data metadata and SARIF-style file locations for findings.
Flexible Input Formats Supports standard dependency files (package.json, requirements.txt, etc.) and generic package lists (text, JSON, YAML).
Production-Ready Logging
Configurable verbosity levels with --verbose and --debug flags for troubleshooting and audit trails.
Safe and Fast Read-only operations with no modifications to your code, optimized for scanning large codebases efficiently.
vs. Single-Ecosystem Tools Most security scanners focus on one package manager. OreWatch provides unified protection across six major ecosystems, essential for modern polyglot development environments.
vs. Manual Threat Lists Static malicious package lists become outdated quickly. Our automated collectors fetch fresh threat intelligence daily from multiple authoritative sources.
vs. Package-Name-Only Detection Checking package names alone misses sophisticated attacks. IoC detection identifies malicious code patterns even in packages not yet on blocklists.
vs. Manual Security Audits Manual dependency reviews are time-consuming and error-prone. Automated scanning enables continuous security validation in every build.
vs. Commercial Black-Box Tools Proprietary tools lack transparency in detection logic. As an open-source project, every detection rule and data source is auditable.
Origin Story OreWatch was born from the development of OreNPMGuard, a specialized scanner for Shai-Hulud npm attacks. During that project, we recognized the need for broader multi-ecosystem coverage beyond npm. In December 2025, we extracted and enhanced the multi-ecosystem detection capabilities into this standalone tool, maintaining OreNPMGuard's focus on npm while enabling OreWatch to serve the wider developer community across all major package ecosystems.
If you are adopting OreWatch for the first time, pick the smallest path that matches your workflow:
Recommended first-run sequence for most developers:
pip install . or the published package.orewatch monitor quickstart /path/to/project --client <your-client>.orewatch monitor status.orewatch monitor menubar for notifications and a local UI.If you want a shorter setup guide with copy-paste commands, use docs/adoption-guide.md.
OreWatch can be installed via pipx (recommended), Homebrew (macOS),
pip, or from source. All methods produce the orewatch CLI command.
pipx installs OreWatch into its own isolated
environment while making the orewatch command available globally. This is the
best option for most developers.
# Install pipx if you don't have it
python3.14 -m pip install --user pipx
python3.14 -m pipx ensurepath
# Install OreWatch
pipx install --python python3.14 orewatch
# If you want the macOS menu bar app on a fresh install, use this instead:
# pipx install --python python3.14 'orewatch[mac-menubar]'
# Verify
orewatch --help
# Optional macOS menu bar app
orewatch monitor menubar
If you already installed orewatch with pipx and want to add the macOS menu
bar app later, inject the Cocoa bindings into the same pipx environment:
pipx inject orewatch pyobjc-framework-Cocoa
Upgrade:
pipx upgrade orewatch
Uninstall:
pipx uninstall orewatch
For macOS users who prefer Homebrew-managed installs:
# Add the OreWatch tap
brew tap rapticore/tap
# Install
brew install rapticore/tap/orewatch
# Verify
orewatch --help
# Optional macOS menu bar app
orewatch monitor menubar
Upgrade:
brew update && brew upgrade orewatch
Uninstall:
brew uninstall orewatch
brew untap rapticore/tap # optional — removes the tap
Note: The Homebrew formula includes the Cocoa bindings required by
orewatch monitor menubar. If an older Homebrew install reportsModuleNotFoundError: No module named 'AppKit', runbrew update && brew reinstall rapticore/tap/orewatchso the formula rebuilds its isolated Python environment with menu bar support.
Use pip for CI pipelines, Docker images, or when you manage your own
virtualenvs:
# Install into an active Python 3.14 virtualenv or user site
python3.14 -m pip install orewatch
# Pin a version for reproducible CI builds
python3.14 -m pip install orewatch==1.3.0
# If you want the macOS menu bar app on a fresh install, use this instead:
# python3.14 -m pip install 'orewatch[mac-menubar]'
# Verify
orewatch --help
Upgrade:
python3.14 -m pip install --upgrade orewatch
# Clone the repository
git clone https://github.com/rapticore/ore-mal-pkg-inspector.git
cd ore-mal-pkg-inspector
# Create and activate a Python 3.14 virtual environment (recommended)
python3.14 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install in editable mode for development
python -m pip install -e .
# Verify
orewatch --help
After installing with any method, confirm OreWatch is working:
# Check the CLI is accessible
orewatch --help
# List supported manifest filenames
orewatch --list-supported-files
# Run a quick scan on the current directory
orewatch .
Python 3.14 is required. OreWatch uses language features introduced in Python 3.14. Older versions will fail at import time.
Note: If local threat data is missing or stale, package scans stage a live-update candidate and only promote it after anomaly gates pass. If the candidate looks suspicious, OreWatch keeps the last-known-good dataset active.
Installed CLI: orewatch
Compatibility alias: ore-mal-pkg-inspector
Scan a project directory:
# Auto-detect ecosystem and scan current directory
orewatch .
# Scan specific project path
orewatch /path/to/your/project
# With verbose output to see progress
orewatch /path/to/your/project --verbose
Expected output:
Detected multiple ecosystems: npm, pypi
Scanning all detected ecosystems...
Scanning npm...
Found 2 dependency file(s) for npm
Parsing: package.json
Parsing: package-lock.json
Scanning pypi...
Found 1 dependency file(s) for pypi
Parsing: requirements.txt
Extracted 45 unique package(s) across 2 ecosystem(s)
Checking 45 package(s) against malicious databases...
Checking 30 npm package(s)...
Checking 15 pypi package(s)...
Scanning for Indicators of Compromise...
Generating report...
============================================================
SCAN REPORT SUMMARY
============================================================
Ecosystem: npm, pypi
Total Packages Scanned: 45
Malicious Packages Found: 0
IoCs Found: 0
✅ No malicious packages or IoCs detected
HTML report saved to: scan-output/malicious_packages_report_20251231_120000.html
JSON report saved to: scan-output/malicious_packages_report_20251231_120000.json
============================================================
If you want OreWatch to keep watching the project after this first scan, continue with Background Monitoring or jump straight to docs/adoption-guide.md.
Scan Directory (Auto-detect ecosystem):
# Current directory
orewatch .
# Specific directory
orewatch /home/user/projects/my-app
# With an absolute path
orewatch /home/user/projects/backend-api
Scan Specific Dependency Files:
# Ecosystem auto-detected from filename
orewatch --file package.json
orewatch --file requirements.txt
orewatch --file pom.xml
orewatch --file Gemfile
orewatch --file go.mod
orewatch --file Cargo.toml
Force Specific Ecosystem:
# Override auto-detection
orewatch /path/to/project --ecosystem npm
orewatch /path/to/project --ecosystem pypi
orewatch /path/to/project --ecosystem maven
orewatch /path/to/project --ecosystem rubygems
orewatch /path/to/project --ecosystem go
orewatch /path/to/project --ecosystem cargo
Scan Generic Package Lists:
# Text file (one package per line) - must specify ecosystem
orewatch --file packages.txt --ecosystem pypi
# JSON file with package array
orewatch --file packages.json --ecosystem npm
# YAML file
orewatch --file packages.yaml --ecosystem npm
Custom Output Path:
# Save to custom location
orewatch /path/to/project --output /tmp/scan_report.json
# Save to specific subdirectory
orewatch /path/to/project --output reports/security/$(date +%Y%m%d).json
IoC Scanning Control:
# Full scan (packages + IoCs) - default behavior
orewatch /path/to/project
# Skip IoC scanning for faster package-only checks
orewatch /path/to/project --no-ioc
# Only scan for IoCs, skip package database checking
orewatch /path/to/project --ioc-only
Quiet Mode:
# Generate report without console summary (useful for scripts)
orewatch /path/to/project --no-summary
Threat Data Controls:
# Force a staged live refresh of the default core sources before scanning
orewatch /path/to/project --latest-data
# Fail if any requested ecosystem only has partial or missing threat data
orewatch /path/to/project --strict-data
# Include experimental sources during collection
orewatch /path/to/project --latest-data --include-experimental-sources
# Print the exact dependency filenames the scanner recognizes
orewatch --list-supported-files
Batch Scanning:
# Scan multiple projects
for dir in ~/projects/*/; do
echo "Scanning $dir"
orewatch "$dir" --output "reports/$(basename $dir).json"
done
The repository now includes a local background monitor that keeps threat data fresh, watches opted-in projects for manifest and workflow changes, runs debounced scans, and records notifications for new or escalated findings. Monitor-owned config and state are stored outside the repo in user-owned directories so a cloned repository cannot preseed monitor behavior.
OreWatch now treats the monitor as a per-user singleton. One daemon can watch many projects anywhere on disk and serve many concurrent Claude Code, Codex, Cursor, VS Code, JetBrains / PyCharm, and Xcode clients.
1. Install and bootstrap the singleton monitor
# First project + first client
orewatch monitor quickstart /path/to/project --client claude_code
monitor quickstart is the recommended first-run flow. It:
If you prefer to install the monitor first and wire clients later:
orewatch monitor install
orewatch monitor install --ide-bootstrap
orewatch monitor install --service-manager launchd --no-start
2. Verify the monitor is healthy
orewatch monitor status
orewatch monitor connection-info
orewatch monitor doctor
Use these commands for slightly different jobs:
monitor status shows whether the singleton daemon and API are runningmonitor connection-info prints the loopback API URL, token path, monitor home, and supported bootstrap clientsmonitor doctor prints the exact config, state DB, log, and shared threat-data paths3. Add every project you want the singleton to watch
orewatch monitor watch add /path/to/project-a
orewatch monitor watch add /path/to/project-b
orewatch monitor watch list
orewatch monitor watch remove /path/to/project-b
One OreWatch daemon can watch all of these projects at once. You do not need a separate monitor per repository or per IDE workspace.
OreWatch supports two integration transports:
The bootstrap commands print one of these shapes:
{
"mcpServers": {
"orewatch": {
"command": "/absolute/path/to/orewatch",
"args": [
"monitor",
"mcp"
]
}
}
}
When orewatch monitor ide-bootstrap --client <client> can resolve the local console script, it now emits that absolute path instead of bare orewatch. If you have an older MCP config that still says "command": "orewatch", regenerate it and replace the old entry.
{
"orewatch": {
"baseUrl": "http://127.0.0.1:48736",
"tokenPath": "/path/to/api.token"
}
}
These clients all use the same local MCP bridge:
orewatch monitor mcp
Recommended setup:
orewatch monitor quickstart /path/to/project --client <cursor|claude_code|codex> once.orewatch_healthorewatch_check_dependency_addorewatch_check_manifestorewatch_override_dependency_addorewatch_list_active_findingsorewatch_list_notificationsNotes:
monitor mcp is a stdio server. If you launch it manually, it will appear idle while waiting for an MCP client.auto_start_on_client is enabled.monitor install so the daemon is already available before the MCP bridge starts.VS Code integrations should use the singleton localhost API rather than the MCP bridge.
Recommended setup:
orewatch monitor quickstart /path/to/project --client vscode.baseUrl and tokenPath from orewatch monitor ide-bootstrap --client vscode.Recommended API usage for a VS Code integration:
POST /v1/check/dependency-add before package-manager install/add flowsPOST /v1/check/manifest when a supported manifest is saved or explicitly recheckedGET /v1/findings/active and GET /v1/notifications to surface background detectionsJetBrains and PyCharm use the same localhost API contract as VS Code.
Recommended setup:
orewatch monitor quickstart /path/to/project --client jetbrains.orewatch monitor ide-bootstrap --client jetbrains.baseUrl and tokenPath in a JetBrains plugin, external tool, or local helper.Recommended API usage for a JetBrains integration:
POST /v1/check/dependency-addpackage.json, requirements.txt, pyproject.toml, pom.xml, Gemfile, go.mod, Cargo.toml, and related supported manifests with POST /v1/check/manifestGET /v1/findings/active and GET /v1/notifications for persistent alert panels or tool windowsXcode integrations should also use the singleton localhost API, but there is an important scope boundary: OreWatch does not yet parse native Apple dependency manifests such as Package.resolved, Podfile.lock, or Cartfile. Today, Xcode integration is best for:
package.json, pyproject.toml, or Cargo.tomlRecommended setup:
orewatch monitor quickstart /path/to/project --client xcode.orewatch monitor ide-bootstrap --client xcode.baseUrl and tokenPath from a build-phase script, a helper process, or a custom Xcode integration.GET /v1/findings/active and GET /v1/notifications for user-visible alerts.POST /v1/check/manifest for those files as part of your workflow.Current integration status:
When the background monitor detects a compromised package or IoC in a watched project, OreWatch:
reports/ directoryUse the built-in CLI review surface to inspect those alerts:
orewatch monitor findings
orewatch monitor findings --project /path/to/project --min-severity high
orewatch monitor notifications
orewatch monitor notifications --project /path/to/project
orewatch monitor package-updates
orewatch monitor package-updates --check
The local API and MCP bridge expose the same data for IDEs and agents:
GET /v1/findings/activeGET /v1/notificationsGET /v1/package-updatesPOST /v1/package-updates/checkorewatch_list_active_findingsorewatch_list_notificationsorewatch_list_package_updatesorewatch_check_package_updatesThis is the supported path for IDEs, MCP clients, and coding agents to surface background detections after the original scan has finished.
Package update advisories are notify-only. OreWatch reports newer versions for watched project dependencies and OreWatch itself, but it does not modify manifests, lockfiles, or installed packages.
OreWatch now includes a macOS-native menu bar app for people who want a visible local UI instead of relying only on CLI commands, MCP polling, or best-effort Notification Center popups.
Install the optional Cocoa bindings into the same runtime that provides the
orewatch command. Choose the command that matches your install method:
# pip / source-checkout install
python3.14 -m pip install 'orewatch[mac-menubar]'
# existing pipx install
pipx inject orewatch pyobjc-framework-Cocoa
# Homebrew install
brew install rapticore/tap/orewatch
Then launch the menu bar app:
orewatch monitor menubar
By default, monitor menubar relaunches the app in the background and returns your shell prompt immediately. Use orewatch monitor menubar --foreground only when you explicitly want to keep it attached to the terminal for debugging.
The menu bar app attaches to the same singleton monitor. It does not start a second monitor instance. If the monitor is not already installed and running, the app will install/start it on first launch.
Homebrew installs the Cocoa bindings into OreWatch's isolated libexec
environment. If orewatch monitor menubar reports No module named 'AppKit',
refresh the formula with brew update && brew reinstall rapticore/tap/orewatch.
For pip, pipx, and source installs, the optional bindings still need to be added
to the same Python environment that provides the orewatch command.
When desktop notifications are enabled on macOS, the singleton watcher now keeps one singleton menu bar app alive and uses it as the primary popup surface. That avoids relying only on a detached osascript invocation from the daemon and gives you a persistent native UI for new findings.
The current menu bar build is icon-first. The old OW shorthand and earlier OreWatch icon wording should be treated as legacy references; the app now prefers the bundled branded icon and only falls back to compact text or badges when macOS cannot render the image or needs an alert count.
What the macOS menu bar app gives you:
Add Workspace Folder... action that enrolls a project into the singleton watcher and runs an initial quick scanRecommended Mac flow:
orewatch monitor quickstart /path/to/project --client claude_code once.orewatch.orewatch monitor menubar.For easier rollout, use the focused docs instead of reading the full README end to end:
Recommended adoption order:
monitor quickstart.orewatch monitor findings and orewatch monitor notifications.monitor menubar so users get a persistent review surface and popup delivery.Common operational commands:
# Background service lifecycle
orewatch monitor start
orewatch monitor restart
orewatch monitor stop
orewatch monitor uninstall
# Run the daemon in the foreground
orewatch monitor run
# Launch the native macOS menu bar UI
orewatch monitor menubar
# Trigger immediate scans
orewatch monitor scan-now
orewatch monitor scan-now /path/to/project
# Review detections and alerts
orewatch monitor findings
orewatch monitor notifications
# Reclaim disk space — prune accumulated backup manifests and orphaned staging
orewatch monitor cleanup
orewatch monitor cleanup --keep-backups 5 --staging-max-age-seconds 3600
Manual snapshot and signing actions:
# Generate a signing keypair
orewatch monitor snapshot keygen /tmp/ore-keys
# Build and apply local threat-data snapshots
orewatch monitor snapshot build /tmp/ore-snapshot \
--private-key /tmp/ore-keys/snapshot_signing_private.pem \
--public-key /tmp/ore-keys/snapshot_signing_public.pem
orewatch monitor snapshot apply /tmp/ore-snapshot/manifest.json \
--public-key /tmp/ore-keys/snapshot_signing_public.pem
# Publish a hosted snapshot channel
orewatch monitor snapshot publish /tmp/ore-snapshots \
--base-url https://example.com/ore-snapshots \
--channel stable \
--private-key /tmp/ore-keys/snapshot_signing_private.pem \
--public-key /tmp/ore-keys/snapshot_signing_public.pem
Monitor behavior:
~/.config/orewatch/singleton/ and state defaults to ~/.local/state/orewatch/singleton/.~/Library/Application Support/OreWatch/singleton/ and state defaults to ~/Library/Application Support/OreWatch/State/singleton/.threat-data/final-data/.monitor doctor prints the exact config_path, state_db, log_file, final_data_dir, and service-template directory for the singleton monitor..ore-monitor.yml at the project root.Local integration surface:
127.0.0.1:48736 by default when the monitor daemon is running.api.token with owner-only permissions.127.0.0.1:48736 without Authorization: Bearer <token> will correctly return 401 Unauthorized.orewatch monitor connection-info rather than guessing paths, and should send the actual project_path they are operating on inside dependency-check requests.orewatch_health, orewatch_check_dependency_add, orewatch_check_manifest, orewatch_override_dependency_add, orewatch_list_active_findings, , , and .Optional anomaly-gated live-update config:
live_updates:
enabled: true
mode: gated
bootstrap_from_live: true
block_on_core_source_failure: false
max_drop_ratio: 0.40
max_drop_absolute: 200
max_removal_ratio: 0.25
max_removal_absolute: 100
warn_growth_ratio: 5.0
warn_growth_absolute: 2000
Key behavior:
Optional notification webhook config:
notifications:
desktop: true
terminal: true
webhook_url: https://hooks.example.com/orewatch
webhook_format: generic
webhook_timeout_ms: 5000
webhook_headers:
Authorization: Bearer change-me
Set webhook_format: slack when targeting a Slack incoming webhook. In that mode OreWatch sends a simple text payload.
The project now has two distinct distribution surfaces:
They should be distributed separately.
Best default for developers: publish the scanner as a normal Python package to PyPI and recommend installation with pipx.
Why this is the best fit:
pipx gives developers an isolated, user-level install without polluting project virtualenvs.python3.14 -m pip install orewatch==<version>.Recommended release shape:
sdist and universal wheel artifacts to PyPI.orewatch console entry point.ore-mal-pkg-inspector as a temporary compatibility alias.pipx install --python python3.14 orewatch for local developer installs.python3.14 -m pip install orewatch==<version> for CI and pinned automation.Available secondary channel: the Homebrew tap is now live for macOS users who prefer Brew-managed installs:
brew install rapticore/tap/orewatch
Homebrew remains a convenience layer over the published PyPI release, not the primary release artifact.
Best option for contributors: keep the current source-checkout flow:
git clone https://github.com/rapticore/ore-mal-pkg-inspector.git
cd ore-mal-pkg-inspector
python3.14 -m venv .venv
source .venv/bin/activate
python -m pip install -e .
If you are rolling OreWatch out with Kandji, Jamf Pro, Intune, Munki, or another macOS software-distribution system, the recommended model is different from the developer pipx path.
Current product reality:
.pkg built around the published OreWatch wheelRecommended enterprise rollout model:
.pkg that installs the OreWatch runtime and a stable orewatch CLI shimmac-menubar extra if you want the native menu bar app on managed Macsorewatch monitor quickstart /path/to/project --client <client> or an equivalent user-context bootstrapWhy this split matters:
Recommended package shape for managed macOS:
/Library/Application Support/OreWatch/runtime/usr/local/bin/orewatchVendor-specific guidance:
.pkg).pkg over .dmg or .zip for OreWatch because the runtime is not a drag-and-drop app.pkg as a Package and deploy it with a Policy or Self Service.pkg.pkg, signed with a Developer ID Installer certificate, and the package must contain a payload.pkg plus pkg metadata and treat OreWatch like other managed macOS softwareFor a fuller rollout playbook, see docs/managed-rollout.md.
Threat-data snapshots should not be bundled inside the Python package. They change on a different cadence and are already supported as signed hosted artifacts.
Open-source/community default: consume openssf and osv directly through the anomaly-gated live-update path.
Enterprise default: publish versioned signed snapshots to static HTTPS hosting and let clients refresh them independently.
Recommended hosting targets:
Recommended snapshot layout:
versions/<version>/manifest.jsonversions/<version>/*.dbchannels/stable.jsonRecommended trust model:
For a production release, the cleanest setup is:
pipxpipBy default, the scanner shows only warnings, errors, and the final summary. For troubleshooting or detailed progress tracking, use the logging flags:
See progress messages and collection statistics:
orewatch /path/to/project --verbose
Output includes:
Example:
INFO: Detected ecosystems: npm, pypi
INFO: Loaded database for npm: 15234 malicious packages
INFO: Loaded database for pypi: 8421 malicious packages
INFO: Extracted 45 packages from 3 files
INFO: Checking 30 npm packages against database...
INFO: Checking 15 pypi packages against database...
INFO: IoC scan complete: 0 indicators found
See detailed diagnostic information for troubleshooting:
orewatch /path/to/project --debug
Output includes:
Use cases:
The threat intelligence collectors also support verbose and debug modes:
cd collectors
# See collection progress
python3 orchestrator.py --verbose
# Debug data source issues
python3 orchestrator.py --debug
Note: All logs go to stderr, keeping stdout clean for JSON report output. This enables piping scanner results to other tools without log message interference.
Reports are saved to the scan-output/ directory by default (or a custom path with --output). OreWatch writes a machine-readable JSON report and a styled HTML companion report with the same basename. The JSON artifact includes threat-data availability metadata and uses SARIF-style physicalLocation objects for package findings, but it is not a full SARIF 2.1.0 document.
Example report:
{
"scan_timestamp": "2025-12-31T12:00:00Z",
"ecosystem": "npm",
"scanned_path": "/path/to/project",
"total_packages_scanned": 150,
"data_status": "complete",
"sources_used": ["openssf", "osv"],
"experimental_sources_used": [],
"missing_ecosystems": [],
"malicious_packages_found": 2,
"iocs_found": 3,
"malicious_packages": [
{
"name": "malicious-pkg",
"version": "1.0.0",
"severity": "critical",
"sources": ["threat-intel-db", "research-community"],
"description": "Malicious code executes unauthorized operations",
"detected_behaviors": ["malicious_code", "data_exfiltration"]
}
],
"iocs": [
{
"type": "malicious_bundle_js",
"path": "node_modules/suspect-pkg/bundle.js",
"hash": "46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09",
"severity": "CRITICAL",
"variant": "original",
"description": "Known malicious payload file from Shai-Hulud attack"
},
{
"type": "malicious_postinstall",
"path": "package.json",
"pattern": "node bundle.js",
"severity": "CRITICAL",
"variant": "original",
"description": "Malicious postinstall hook executes payload"
}
]
}
Threat data fields:
data_status: complete, partial, failed, or not_applicablesources_used: sources that contributed usable threat data for the requested ecosystemsexperimental_sources_used: experimental sources included in the scan datamissing_ecosystems: requested ecosystems that had no usable package-threat databasepromotion_decision: empty for existing-data scans, otherwise promoted, bootstrapped, or rejectedkept_last_known_good: true when a live candidate was rejected but the previous active dataset remained usableSeverity Levels:
Recommended Actions:
Basic Security Scan:
name: Security Scan - Malicious Packages
on: [push, pull_request]
jobs:
malicious-package-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.14'
- name: Install OreWatch
run: |
git clone https://github.com/rapticore/ore-mal-pkg-inspector.git scanner
cd scanner
pip install .
- name: Scan for malicious packages
run: |
cd scanner
orewatch ${{ github.workspace }} --latest-data
- name: Upload scan report
uses: actions/upload-artifact@v4
if: always()
with:
name: security-scan-report
path: scanner/scan-output/
Advanced with Failure on Detection:
- name: Scan and fail on malicious packages
run: |
cd scanner
orewatch ${{ github.workspace }} --latest-data --output report.json
# Check if malicious packages were found
MALICIOUS_COUNT=$(jq '.malicious_packages_found' report.json)
IOC_COUNT=$(jq '.iocs_found' report.json)
if [ "$MALICIOUS_COUNT" -gt 0 ] || [ "$IOC_COUNT" -gt 0 ]; then
echo "🚨 SECURITY ALERT: Malicious packages or IoCs detected!"
echo "Malicious packages: $MALICIOUS_COUNT"
echo "IoCs found: $IOC_COUNT"
exit 1
fi
malicious-package-scan:
image: python:3.14
stage: security
before_script:
- git clone https://github.com/rapticore/ore-mal-pkg-inspector.git scanner
- cd scanner && pip install .
script:
- orewatch $CI_PROJECT_DIR --latest-data --strict-data --output scan-report.json
artifacts:
paths:
- scan-report.json
when: always
allow_failure: false
pipeline {
agent any
stages {
stage('Setup Scanner') {
steps {
sh '''
git clone https://github.com/rapticore/ore-mal-pkg-inspector.git scanner
cd scanner
python3.14 -m pip install .
'''
}
}
stage('Security Scan') {
steps {
sh '''
cd scanner
orewatch ${WORKSPACE} --latest-data
'''
}
}
}
post {
always {
archiveArtifacts artifacts: 'scanner/scan-output/*.json', fingerprint: true
}
}
}
Add to .git/hooks/pre-commit:
#!/bin/bash
echo "Running malicious package scan..."
cd /path/to/ore-mal-pkg-inspector
orewatch $PROJECT_DIR --no-summary
if [ $? -ne 0 ]; then
echo "❌ Malicious packages or IoCs detected! Commit blocked."
echo "Review the scan report in scan-output/"
exit 1
fi
echo "✅ Security scan passed"
Symptom:
ERROR: No usable threat data available for requested ecosystems: npm
Cause: Threat-data collection failed, metadata is incomplete, or the requested ecosystems do not have usable local databases yet.
Solution:
# Force recollection and require a complete result for the requested ecosystems
orewatch /path/to/project --latest-data --strict-data
Note: If this persists, check network connectivity, filesystem permissions, and whether you intentionally requested experimental sources.
Symptom:
WARNING: No packages detected in /path/to/project
Possible causes and solutions:
Wrong directory: Ensure you're scanning the correct project directory
ls /path/to/project # Verify package.json or requirements.txt exists
Unsupported or unexpected manifest: Print the exact supported filenames
orewatch --list-supported-files
File permissions: Ensure files are readable
ls -la /path/to/project/package.json
Symptom:
ERROR: Error downloading npm: <urlopen error [Errno -3] Temporary failure in name resolution>
Solutions:
Check internet connection:
ping google.com
Retry with timeout increase: Edit collectors/config.yaml:
osv:
timeout: 600 # Increase from default 300
Use cached data: If you have previously downloaded data:
python3 orchestrator.py --skip-build # Skip download, rebuild from cache
Symptom:
ERROR: Error creating directory collectors/raw-data: Permission denied
Solution:
# Ensure proper ownership
sudo chown -R $USER:$USER /path/to/ore-mal-pkg-inspector
# Or run from user-writable location
cd ~/
git clone https://github.com/rapticore/ore-mal-pkg-inspector.git
cd ore-mal-pkg-inspector
Symptom: ~/Library/Application Support/OreWatch (macOS) or
$XDG_STATE_HOME/orewatch (Linux) has grown into the tens of gigabytes.
Cause (pre-1.2.3): Every live-update promotion archived a full copy of the previous threat-data databases (~300 MB) without retention. A long-running monitor accumulated one snapshot per cycle indefinitely.
Fix: Upgrade to 1.2.3 or later. Backups are now ~1 KB SHA-256 manifests, retention defaults to the most recent 30, and an explicit cleanup command is available:
# Apply the configured retention policy now (default: keep 30 manifests,
# remove staging entries older than 1 hour).
orewatch monitor cleanup
# Reclaim everything except the most recent 5 backups and purge staging.
orewatch monitor cleanup --keep-backups 5 --staging-max-age-seconds 0
# Tune retention in monitor config (live_updates section):
# retain_backups: <int> # how many backup manifests to keep
# staging_max_age_seconds: <int> # stale candidate-* staging cutoff
Symptom: Legitimate package flagged as malicious.
Steps:
Verify the finding: Review the report details including severity and description
Check version: The flagged version may be specific:
orewatch /path/to/project --verbose
Report false positive: If confirmed incorrect:
Enable detailed logging:
# Scanner debug mode
orewatch /path/to/project --debug 2> debug.log
# Collector debug mode
cd collectors
python3 orchestrator.py --debug 2> collector-debug.log
Review logs: Check debug.log for detailed execution trace including:
Recommendation:
Malicious packages are published continuously. Daily updates ensure the latest protections.
Run the scanner with the --latest-data flag to force an update:
orewatch /path/to/project --latest-data
For automated updates in CI/CD, schedule periodic scans with --latest-data flag (e.g., daily). Add --include-experimental-sources only if you explicitly want Phylum-derived data included in the rebuild.
Note: First-time scans automatically collect data, so manual updates are only needed to refresh existing databases.
The default databases are built from the project’s core threat sources:
openssfosvThe scanner can also include the project’s experimental source set:
phylum with --include-experimental-sourcessocketdev is present in the repository as a disabled placeholder and is not part of the default collection path.
For technical details about data sources, collection, and processing, see ARCHITECTURE.md.
No. OreWatch performs read-only operations. It:
It never:
Steps to take:
Partially.
Offline scanning: ✅ Yes, once databases are initialized
# Online: Initial setup (one-time - runs automatically on first scan)
orewatch /path/to/project
# Offline: Subsequent scans work with local databases
orewatch /path/to/project
Offline updates: ❌ No, threat intelligence collection requires internet access to fetch from security sources.
Airgapped environments: You can:
final_data_dir shown by orewatch monitor doctorDifferent purposes:
npm audit / pip-audit:
OreWatch:
Best practice: Use both:
# Check for vulnerabilities
npm audit
pip-audit
# Check for malicious packages
orewatch /path/to/project
Dependency scanning: ✅ Yes, the scanner reads your dependency files regardless of where packages come from.
Threat intelligence: ⚠️ Limited. Our databases cover public registries (npmjs.com, pypi.org, etc.). Malicious packages on private registries won't be detected unless you add custom threat data.
Custom threat data: You can extend the databases with your own malicious package lists. Contact us for guidance on this advanced use case.
Scan time:
Factors:
--no-ioc if not needed)Optimization tips:
# Scan specific files instead of entire directory
orewatch --file package.json
We welcome contributions! Whether you're reporting bugs, suggesting features, or contributing code, your help improves OreWatch for everyone.
Report bugs or request features:
Contribute code:
Questions or discussions:
Security is our top priority. OreWatch is a security tool, and we take vulnerabilities seriously.
Do NOT open public GitHub issues for security vulnerabilities.
Instead, report privately:
Email: [email protected]
Include:
When using OreWatch:
Do:
Don't:
We follow coordinated disclosure:
We recognize security researchers who responsibly disclose vulnerabilities:
List will be maintained as reports are received
Vote on or suggest features:
We prioritize features based on:
To influence the roadmap:
OreWatch is usable today for:
Near-term priorities:
Mid-term priorities:
Known current boundary:
Package.resolved, Podfile.lock, or Cartfile.Longer-term direction:
See docs/roadmap.md for the more adoption-focused roadmap view.
MIT License
Copyright (c) 2025 Rapticore
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Documentation: You're reading it! Start here for most questions.
GitHub Discussions: For questions, ideas, and community interaction:
GitHub Issues: For bug reports and feature requests:
Email: For security vulnerabilities and private inquiries:
For organizations requiring:
Contact: [email protected]
This project was extracted from the OreNPMGuard repository to maintain clear project focus while expanding capabilities.
OreNPMGuard (December 2025) specializes in Shai-Hulud npm attack detection with 738+ affected packages and deep IoC analysis. During its development, we recognized the need for broader multi-ecosystem protection, leading to the creation of OreWatch as a standalone tool serving the wider developer community across all major package ecosystems.
Built by Rapticore Security Research Team
Protecting software supply chains, one scan at a time.
| I want to... | Use this path | Start with |
|---|
| scan one repo right now | CLI scan | orewatch /path/to/project |
| protect local development in the background | singleton monitor | orewatch monitor quickstart /path/to/project --client claude_code |
| use OreWatch from Cursor, Claude Code, or Codex | MCP bridge | `orewatch monitor quickstart /path/to/project --client <cursor |
| integrate with VS Code, PyCharm, or Xcode | localhost API | orewatch monitor quickstart /path/to/project --client vscode |
| get visible macOS alerts and a native review surface | menu bar app | orewatch monitor menubar |
| validate builds in CI | one-off CLI scan | orewatch . --strict-data |
| Platform | Python Source | Notes |
|---|
| macOS (Homebrew Python) | brew install [email protected] | Recommended for Homebrew users |
| macOS (pyenv) | pyenv install 3.14 | Best for multi-version setups |
| Ubuntu / Debian | sudo apt install python3.14 or pyenv | Check your distro ships 3.14+ |
| Fedora / RHEL | sudo dnf install python3.14 or pyenv | — |
| Windows (WSL) | pyenv or system package | Native Windows is untested |
| Symptom | Fix |
|---|
command not found: orewatch | Ensure the install location is on your PATH. For pipx: run pipx ensurepath and restart your shell. |
ModuleNotFoundError on import | You may have multiple Python versions. Confirm the runtime behind orewatch is Python 3.14+ and reinstall with the matching interpreter. |
| pipx install fails with resolver errors | Upgrade pipx: python3.14 -m pip install --upgrade pipx |
Homebrew orewatch not found after install | Run brew tap rapticore/tap first, then retry the install. |
| Permission denied during pip install | Use pip install --user orewatch or install inside a virtualenv. |
| Option | Short | Description | Default |
|---|
--file | -f | Path to specific file to scan (skips directory detection) | None |
--ecosystem | -e | Force ecosystem: npm, pypi, maven, rubygems, go, cargo | Auto-detect |
--output | -o | Custom output path for the primary JSON report; OreWatch also writes a sibling HTML report | scan-output/malicious_packages_report_{timestamp}.json |
--no-summary | Skip printing report summary to console | False | |
--no-ioc | Skip IoC (Indicators of Compromise) scanning | False | |
--ioc-only | Only scan for IoCs, skip package checking | False | |
--latest-data | Force a staged live refresh and anomaly-gated promotion before scanning | False | |
--strict-data | Fail if any requested ecosystem has partial or missing threat data | False | |
--include-experimental-sources | Include experimental collectors during threat-data refresh | False | |
--list-supported-files | Print the exact supported dependency manifest filenames and exit | False | |
--verbose | -v | Show INFO level logs (progress messages) | False |
--debug | Show DEBUG level logs (detailed diagnostics) | False |
| Client | Transport | Bootstrap Command | Notes |
|---|
| Claude Code | MCP | orewatch monitor ide-bootstrap --client claude_code | First-class MCP bridge |
| Codex | MCP | orewatch monitor ide-bootstrap --client codex | First-class MCP bridge |
| Cursor | MCP | orewatch monitor ide-bootstrap --client cursor | First-class MCP bridge |
| VS Code | Local API | orewatch monitor ide-bootstrap --client vscode | No bundled extension; use the localhost API |
| JetBrains / PyCharm | Local API | orewatch monitor ide-bootstrap --client jetbrains | No bundled plugin; use the localhost API |
| Xcode | Local API | orewatch monitor ide-bootstrap --client xcode | Best for findings/notifications and mixed-language repos |
monitor install now installs a user-level launchd or systemd service when available, and falls back to the local background mode otherwise.monitor quickstart /path/to/project --client claude_code is the easiest first-run flow for a local LLM agent setup.--workspace-root /path/to/workspace is still accepted for one release as a deprecated compatibility alias, but it no longer changes monitor identity, token location, or service naming.auto mode, if native launchd or systemd setup fails, OreWatch now falls back to the local background mode instead of aborting setup.monitor install --ide-bootstrap prints copy-paste bootstrap snippets for Claude Code, Codex, Cursor, VS Code, JetBrains / PyCharm, and Xcode.monitor connection-info prints the loopback API base URL, token path, singleton monitor scope/home, and whether the daemon is already running.monitor ide-bootstrap prints the current MCP/API bootstrap snippets again without reinstalling anything.monitor mcp runs a local MCP bridge that exposes OreWatch dependency checks to Claude Code, Codex, and Cursor.monitor findings, monitor notifications, and monitor package-updates provide the built-in review surface for background detections and update advisories.monitor menubar launches a native macOS menu bar app backed by the singleton monitor and findings store.monitor mcp is a stdio server, so it will wait for an MCP client after startup. It now writes readiness and auto-start status to stderr, not stdout.monitor install so the background daemon is already available when the client launches monitor mcp or calls the API.make test-e2e-clients bootstraps the synthetic workspace and runs the cross-ecosystem MCP/API client matrix for Claude Code, Codex, and Cursor.openssf and osv). Candidate data is staged in the user-owned monitor state directory, checked for abnormal drops/removals, and only then promoted into the active databases.snapshots.channel_url or snapshots.manifest_url, and the monitor verifies them with snapshots.public_key_path.openssl on the local machine.orewatch_list_notificationsorewatch_list_package_updatesorewatch_check_package_updatesanomalies: warning/block anomalies raised during a live refresh attempt