Security scanner for ComfyUI custom nodes and node-based workflow plugins
Project description
nodesafe
Security scanner for ComfyUI custom nodes — and the emerging standard for node-based workflow plugin security.
nodesafe scans third-party plugins/nodes before you install them in node-based workflow tools, detecting malicious code with a cascading pipeline that combines static analysis, signature matching, machine learning, and optional semantic analysis with an LLM. Starting point: the ComfyUI ecosystem.
[5-second GIF of the scanner detecting a malicious node — placeholder until v0.1]
Why this exists
In June 2024, ComfyUI_LLMVISION stole browser credentials and crypto wallets from hundreds of users. In April 2026, a botnet compromised 1,000+ ComfyUI instances by auto-installing malicious nodes via the Manager. The custom_nodes ecosystem is large, fast-moving, and largely unverified.
nodesafe scans before you install.
Quick start
pip install nodesafe
nodesafe scan /path/to/custom_node
Or directly without installing:
uvx nodesafe scan /path/to/custom_node
How it works
A 9-layer cascading pipeline. Each layer more expensive than the previous. Most clean nodes pass in <100ms; only ambiguous cases escalate.
| Layer | Technique | Cost |
|---|---|---|
| 0 | Hash matching against malware database | μs |
| 1 | Bloom filter of malicious URLs | μs |
| 2 | Aho-Corasick over dangerous patterns | ms |
| 3 | AST analysis (optional Semgrep backend) | ms |
| 4 | Typosquatting + OSV vulnerability check | ms |
| 5 | ML classifier (Naive Bayes + XGBoost) | tens of ms |
| 6 | Anomaly detection (Isolation Forest + Autoencoder) | tens of ms |
| 7 | Semantic similarity (CodeBERT embeddings + FAISS) | hundreds of ms |
| 8 | LLM review (optional, local-first via Ollama) | seconds |
Current state (v0.3.1): Layers 0-4 functional and shipping on PyPI. 50 tests passing across Python 3.10–3.12 × Linux/macOS/Windows. Layers 5-8 in the M2-M4 roadmap.
Features
- ✓ Pure static analysis — never executes scanned code
- ✓ Zero telemetry by default — this policy is immutable
- ✓ Works offline (after the first signature update)
- ✓ Multiple output formats: JSON, SARIF (GitHub Code Scanning), Markdown
- ✓ GitHub Action ready — see the example workflow
- ✓ Pre-commit hook ready — for CI/CD of custom_nodes repositories
- ✓ Local-first LLM analysis — Ollama by default, cloud opt-in with BYO key
- ✓ OSS Apache 2.0 — no freemium, no hidden SaaS, no paid whitelisting
Usage
Scan a directory
nodesafe scan /path/to/custom_node
JSON output
nodesafe scan /path/to/custom_node --format json
Integrate with GitHub Code Scanning (SARIF)
nodesafe scan custom_nodes/ --format sarif > nodesafe.sarif
Only cheap layers (fast, no ML)
nodesafe scan /path/to/custom_node --layers 0,1,2,3
Update signatures
nodesafe update
Verify installation
nodesafe doctor
Retrospective analysis
Would nodesafe have detected the historical incidents? We apply the pipeline mentally to each case:
| Incident | Detection layer | Time | Verdict |
|---|---|---|---|
| LLMVISION (Jun 2024) | Layer 2-3 | ~30-50ms | malicious 0.98 |
| Pickai (Mar-Jun 2025) | Layer 2-3 + 5-7 | ~100ms | malicious 0.92 |
| Mining botnet (Apr 2026) | Layer 2-3 + Manager gate | <50ms | malicious 0.95 |
Full analysis in docs/retrospective-analysis.md.
Honest limitations
nodesafe is static analysis, not a sandbox. Its limits:
- It does not prevent upstream supply chain attacks (a legitimate provider being compromised). It detects the malware when it is distributed in nodes, not the original compromise.
- It is not a replacement for the Manager — it is complementary; ideally integrated.
- It does not monitor runtime behavior — that is the job of an IDS/EDR.
- False positives happen — the policy is conservative, but every flag shows exactly what triggered the alert so you can decide.
Configuration
~/.config/nodesafe/config.toml (optional — sane defaults):
[scanner]
default_layers = "0,1,2,3,4,5,6" # Layer 8 NOT included by default
fail_on = "suspicious"
[llm]
enabled = false # OFF by default. Conscious opt-in.
provider = "local" # local-first if enabled
[llm.local]
endpoint = "http://localhost:11434" # Ollama
model = "qwen2.5-coder:7b-instruct"
[telemetry]
enabled = false # ALWAYS false. Immutable policy.
Roadmap
- v0.3.x (M1, shipped): Layers 0-4 — hash matching, malicious URLs, Aho-Corasick patterns, AST analysis, typosquatting + OSV. Available now via
pip install nodesafe. - v0.5 (M2): Layer 5 ML (Naive Bayes + XGBoost) + Semgrep backend + first public wave
- v1.0 (M3): Layers 6-7 (anomaly detection + CodeBERT) + PR to ComfyUI-Manager + formal launch
- v1.5 (M4): Layer 8 LLM (Ollama-first) + public threat report + consolidated community
- v2+ (Year 2):
.nodesafestandard portable to other node-based ecosystems
Full plan in ARCHITECTURE.md.
Contributing
PRs welcome. See CONTRIBUTING.md.
Especially welcome:
- Contributions of new malware signatures — see
signatures/README.md - False positive reports for legitimate nodes
- Missed detection reports — open an issue with the
[missed-detection]tag - Semgrep rules specific to ComfyUI / diffusion patterns
Acknowledgments
Inspired by HuggingFace's safetensors push, Snyk Labs' research on ComfyUI attack vectors, and the unfortunate work of u/roblaughter who discovered LLMVISION at his own cost.
License
Apache 2.0. See LICENSE.
Long-term vision
ComfyUI is the most urgent case, not the only one. The full category of node-based tools with executable plugins (LangFlow, Flowise, Node-RED, n8n, etc.) shares the same structural problem. In the long term, .nodesafe aspires to become a portable manifest artifact that any ecosystem can adopt — analogous to how .safetensors became the standard for ML model weights.
V2-V3 of the project formalizes the standard and works with maintainers of other ecosystems. Today, brutal focus on ComfyUI.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nodesafe-0.4.0.tar.gz.
File metadata
- Download URL: nodesafe-0.4.0.tar.gz
- Upload date:
- Size: 46.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c7faa94a2cd628093afa269d37ab959ce74e59802c0b4a40e96d03c3d0bedaa6
|
|
| MD5 |
90928c376a7dadf0877c648177c2b77e
|
|
| BLAKE2b-256 |
add25ddf725eae7ff7fe40eb50e2e932278099dee74882a297343f0aa1bb68cc
|
Provenance
The following attestation bundles were made for nodesafe-0.4.0.tar.gz:
Publisher:
release.yml on neuregex/nodesafe
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nodesafe-0.4.0.tar.gz -
Subject digest:
c7faa94a2cd628093afa269d37ab959ce74e59802c0b4a40e96d03c3d0bedaa6 - Sigstore transparency entry: 1632696246
- Sigstore integration time:
-
Permalink:
neuregex/nodesafe@18bd6922202f28af467b3cab3c54307fb348f928 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/neuregex
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@18bd6922202f28af467b3cab3c54307fb348f928 -
Trigger Event:
push
-
Statement type:
File details
Details for the file nodesafe-0.4.0-py3-none-any.whl.
File metadata
- Download URL: nodesafe-0.4.0-py3-none-any.whl
- Upload date:
- Size: 52.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7bc837d3f15f3a4b6bda5eed69d6027838f0271ae3299df3ee2efd1a7cc1cc8f
|
|
| MD5 |
5063134e873ca63d4be86d7c9eedfff1
|
|
| BLAKE2b-256 |
11c079083a2c398bc4f56adc41578847288ae7e7ae51647a74850087e39919aa
|
Provenance
The following attestation bundles were made for nodesafe-0.4.0-py3-none-any.whl:
Publisher:
release.yml on neuregex/nodesafe
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nodesafe-0.4.0-py3-none-any.whl -
Subject digest:
7bc837d3f15f3a4b6bda5eed69d6027838f0271ae3299df3ee2efd1a7cc1cc8f - Sigstore transparency entry: 1632696309
- Sigstore integration time:
-
Permalink:
neuregex/nodesafe@18bd6922202f28af467b3cab3c54307fb348f928 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/neuregex
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@18bd6922202f28af467b3cab3c54307fb348f928 -
Trigger Event:
push
-
Statement type: