Open-source iterative threat modeling powered by LLMs - STRIDE + MAESTRO frameworks with DREAD scoring
Project description
Paranoid
Open-source, self-hosted, iterative threat modeling powered by LLMs.
Paranoid takes system descriptions (text, diagrams, or code via MCP) and produces comprehensive STRIDE + MAESTRO threat models through an LLM-powered pipeline with deterministic fallback. Configure 1–15 automated iteration passes, then review threats in a human-in-the-loop approve/reject cycle.
Features
- Zero Infrastructure: SQLite + sqlite-vec. One command to run:
docker compose up[Coming Soon] - Multi-Provider LLM: Anthropic, OpenAI, or Ollama (fully local/air-gapped)
- Dual Framework Support: STRIDE (traditional) + MAESTRO (AI/ML) auto-detected or run in parallel
- DREAD Risk Scoring: Automatic risk assessment with 5 dimensions (0-10 scale each, averaged) for severity classification
- Structured Input Templates: Tagged templates for component descriptions with assumption enforcement in the prompts
- Iterative Refinement: 1–15 configurable iteration passes with gap analysis
- Code-as-Input: Semantic code extraction via context-link MCP —
--code /path/to/repogrounds threats in actual implementation - Image-as-Input: Architecture diagram support via
--diagram arch.png(vision API) or--diagram flow.mmd(Mermaid text) - Deterministic Rule Engine: 362 curated patterns (STRIDE, MAESTRO, OWASP, MITRE ATT&CK, ATLAS, CAPEC, cloud misconfigurations) across 16 seed files — run alongside the LLM and merged into the final output
- Persistent Results: Every run is saved to SQLite automatically — inspect past models with
paranoid models list/paranoid models show - Export Formats: JSON (simple/full), SARIF (GitHub Security integration), Markdown (PRs / Confluence / Notion), PDF (security review sign-off)
- Post-Run Export: Re-export any saved model in any format with
paranoid models export— run once, export many times - Model Management:
paranoid models deleteremoves a saved model and all its data;paranoid models prunebulk-deletes by age or status - Pre-flight Gap Analysis: Description completeness check before running — warns about missing auth, trust boundaries, data flows, and external integrations;
--strictexits CI with code 2 on error-severity gaps - Edit Context Before Threats: Review and edit extracted assets, flows, and trust boundaries at
/models/:id/contextbefore or after a run; "Re-extract" re-runs only the extraction steps without regenerating threats - DREAD Score Editing: Edit any threat's DREAD scores inline from the Review page — no page reload required
- Fast Provider Routing: Configurable
FAST_MODELuses a Haiku-class model for extraction and enrichment, reserving Sonnet/Opus for threat generation — cuts API cost without sacrificing quality - Attack Tree & Test Case Enrichment:
--enrichgenerates STRIDE/MAESTRO attack trees and Gherkin test cases per threat after the main pipeline run; included automatically in Markdown and PDF exports - Editable Settings (Web UI): Runtime configuration editing at
/settings— change provider, model, iterations, and more without restarting; protected by optionalCONFIG_SECRETshared secret - CI/CD Ready: CLI + GitHub Action with SARIF upload for automated threat detection
Quick Start
Step 1: Install
Choose the method that works best for you:
PyPI (Recommended):
pip install paranoid-cli
paranoid --version
Docker (self-hosted, web UI + CLI):
git clone https://github.com/theAstiv/paranoid && cd paranoid
# Configure your LLM provider
cp .env.example .env
# Edit .env — at minimum set ANTHROPIC_API_KEY (or OPENAI_API_KEY)
# Build and start (first build: ~5-10 min for Go + Node + Python stages)
docker compose up --build
# Web UI
open http://localhost:8000/app
# API docs (OpenAPI)
open http://localhost:8000/docs
See Running with Docker for build args, offline builds, and CLI usage inside the container.
Standalone Binary (No Python Required):
Download the pre-built binary for your platform from GitHub Releases:
| Platform | Binary |
|---|---|
| Linux x86_64 | paranoid-linux-x64 |
| macOS ARM64 (Apple Silicon) | paranoid-macos-arm64 |
| Windows x64 | paranoid-windows-x64.exe |
# Linux/macOS
chmod +x paranoid-linux-x64
./paranoid-linux-x64 --help
From Source (Development):
git clone https://github.com/theAstiv/paranoid
cd paranoid
pip install -e .
Step 2: Configure
Option A: Interactive Wizard (Recommended)
paranoid config init
# Follow prompts to configure:
# - LLM Provider (Anthropic/OpenAI/Ollama)
# - API Key
# - Model name
# - Default iterations
paranoid config show
Option B: Environment Variables
cp .env.example .env
Edit .env and add your provider configuration:
# Anthropic (Recommended)
ANTHROPIC_API_KEY=sk-ant-api03-xxxxxxxxx
DEFAULT_PROVIDER=anthropic
DEFAULT_MODEL=claude-sonnet-4-20250514
# OR OpenAI
OPENAI_API_KEY=sk-xxxxxxxxx
DEFAULT_PROVIDER=openai
DEFAULT_MODEL=gpt-4o
# OR Ollama (fully local, no API key)
OLLAMA_BASE_URL=http://localhost:11434
DEFAULT_PROVIDER=ollama
DEFAULT_MODEL=llama3
# Optional: path to context-link binary for --code flag
# If unset, Paranoid looks for bin/context-link then PATH
CONTEXT_LINK_BINARY=/usr/local/bin/context-link
# Optional: fast model for extraction/enrichment steps (Anthropic only)
# Defaults to claude-haiku-4-5-20251001; set to same value as DEFAULT_MODEL to disable fast routing
FAST_MODEL=claude-haiku-4-5-20251001
# Optional: shared secret to protect PATCH /config (web UI settings page)
# If set, the Settings page requires this value to save any configuration change
CONFIG_SECRET=your-secret-here
# Optional: restrict CORS origins (default: * allows all)
# Comma-separated for multiple origins
CORS_ORIGINS=https://app.example.com,https://staging.example.com
Step 3: Run Your First Threat Model
# Run with an example
paranoid run examples/stride-example-api-gateway.md
# With architecture diagram (Mermaid, PNG, or JPG)
paranoid run examples/stride-example-api-gateway.md \
--diagram examples/stride-api-gateway-architecture.mmd
# With your own system description
paranoid run my-system.md
# See all options
paranoid run --help
Expected Output:
Configuration:
Provider: anthropic
Model: claude-sonnet-4-20250514
Iterations: 3
Framework: STRIDE
[>] summarize: Generating system summary...
[OK] summarize: Summary generated: 196 chars
[>] extract_assets: Identifying assets and entities...
[OK] extract_assets: Identified 14 assets/entities
[>] extract_flows: Extracting data flows and trust boundaries...
[OK] extract_flows: Identified 12 flows, 6 boundaries
[>] generate_threats [iter 1]: Generating threats (iteration 1/3)...
[OK] generate_threats [iter 1]: Generated 10 threats
...
[OK] complete: Pipeline complete: 2 iterations, 17 threats
================================================================================
THREAT MODEL COMPLETE
================================================================================
Total Threats: 17
Iterations: 2
Duration: 115.0 seconds
Output: stride-example-api-gateway_threats.json
Expected Runtime:
- Claude Sonnet: ~30-60 seconds (3 iterations)
- GPT-4: ~45-90 seconds (3 iterations)
- Ollama (local): 2-5 minutes (depends on hardware)
CLI Reference
Running Threat Models
# Basic usage (auto-detects framework from input)
paranoid run system.md
# Structured templates (auto-detects STRIDE vs MAESTRO)
paranoid run examples/stride-example-api-gateway.md
paranoid run examples/maestro-example-rag-chatbot.md
# JSON output (simple format - lightweight, ~2-3 KB)
paranoid run system.md --output threats.json
# JSON output (full format - complete models + DREAD + events, ~45 KB)
paranoid run system.md --format full -o complete.json
# SARIF export for GitHub Security integration
paranoid run system.md --format sarif -o threats.sarif
# Markdown export for PRs, Confluence, and Notion
paranoid run system.md --format markdown -o threats.md
# Markdown export with auto-suffix (no extension needed)
paranoid run system.md --format markdown -o threats
# PDF export for security review sign-off and archival
paranoid run system.md --format pdf -o report.pdf
# PDF export with auto-suffix
paranoid run system.md --format pdf -o report
# Force dual framework (STRIDE + MAESTRO in parallel)
paranoid run system.md --maestro
# Override iteration count (1-15)
paranoid run system.md --iterations 7
# Override framework auto-detection
paranoid run system.md --framework MAESTRO
# Override provider and model for a single run (without changing config)
paranoid run system.md --provider openai --model gpt-4o
paranoid run system.md --provider anthropic --model claude-opus-4-5
# Quiet mode (suppress real-time output, show only summary)
paranoid run system.md --quiet
# Verbose mode (show detailed event data with complete models)
paranoid run system.md --verbose
# Code-as-input: ground threats in actual source code (requires context-link binary)
paranoid run system.md --code /path/to/repo
# Image-as-input: include architecture diagram (PNG/JPG via vision API)
paranoid run system.md --diagram architecture.png
# Image-as-input: Mermaid diagram as text (all providers)
paranoid run system.md --diagram flow.mmd
# Combined: description + diagram + code context
paranoid run system.md --diagram arch.png --code /path/to/repo
# Strict mode: exit code 2 if description has error-severity gaps (for CI gates)
paranoid run system.md --strict
# Gap warnings are always printed to stderr; --strict makes errors blocking
paranoid run system.md --strict --format sarif -o findings.sarif
# Generate attack trees + Gherkin test cases per threat after the pipeline run
# Requires Anthropic provider; uses FAST_MODEL (claude-haiku-4-5-20251001) if configured
paranoid run system.md --enrich
# Enrich and export to Markdown (attack trees + test cases included in output)
paranoid run system.md --enrich --format markdown -o enriched-report.md
# Enrich and export to PDF
paranoid run system.md --enrich --format pdf -o enriched-report.pdf
Inspecting Saved Models
Every paranoid run saves its results to SQLite automatically. Use the models subcommand to browse and inspect past runs without re-running the pipeline.
# List recent threat models (most recent first)
paranoid models list
# Limit results
paranoid models list --limit 50
# Machine-readable JSON output
paranoid models list --json
# Show threats for a saved model — partial ID works (first 8 chars)
paranoid models show a1b2c3d4
# Full UUID also accepted
paranoid models show a1b2c3d4-e5f6-7890-abcd-ef1234567890
# Show threats without mitigations
paranoid models show a1b2c3d4 --no-mitigations
# JSON output (model metadata + threats array)
paranoid models show a1b2c3d4 --json
# Export a saved model to Markdown (run once, export many times)
paranoid models export a1b2c3d4 --format markdown -o report.md
# Export to PDF for security review sign-off
paranoid models export a1b2c3d4 --format pdf -o report.pdf
# Export to SARIF for GitHub Security
paranoid models export a1b2c3d4 --format sarif -o findings.sarif
# Export to JSON (simple summary or full raw dump)
paranoid models export a1b2c3d4 --format simple -o threats.json
paranoid models export a1b2c3d4 --format full -o complete.json
# Default output path (no -o flag): {id_prefix}_{format}.{ext} in cwd
paranoid models export a1b2c3d4 --format markdown
# Delete a saved model and all its data (prompts for confirmation)
paranoid models delete a1b2c3d4
# Delete without prompt (for scripting/CI)
paranoid models delete a1b2c3d4 --yes
# Prune old models (older than 30 days)
paranoid models prune --older-than 30
# Prune all failed models without prompting
paranoid models prune --status failed --yes
# Combine filters: old AND failed
paranoid models prune --older-than 7 --status failed
Example models list output:
ID Title Framework Threats Status Date
--------------------------------------------------------------------------
a1b2c3d4 api-gateway STRIDE 23 completed 2026-04-01 14:32
e5f6g7h8 auth-service STRIDE 17 completed 2026-03-28 09:15
c9d0e1f2 rag-chatbot MAESTRO 31 completed 2026-03-25 11:04
Example models show output:
Threat Model: api-gateway
============================================================
ID: a1b2c3d4-...
Framework: STRIDE
Threats: 23
Iterations: 3
THREATS
------------------------------------------------------------
[1] SQL Injection (Tampering) pending
Target: PostgreSQL DB | Impact: High | Likelihood: Medium
→ Use parameterized queries
→ Apply input validation
...
Configuration Management
# Interactive setup wizard
paranoid config init
# Reconfigure (overwrite existing config)
paranoid config init --force
# Display current configuration
paranoid config show
# Config file location: ~/.paranoid/config.json
Version Info
# Show version, Python version, dependencies, and current configuration
paranoid version
Running with Docker
The Docker image bundles all three components — FastAPI backend, Svelte frontend, and the context-link MCP binary — into a single container. The frontend is served as static files from FastAPI at /app.
Standard build
git clone https://github.com/theAstiv/paranoid && cd paranoid
cp .env.example .env # copy and edit with your API key
docker compose up --build # builds all three stages, then starts the server
First build takes roughly 5–10 minutes (Go toolchain download + Node modules + Python dependencies + fastembed model pre-bake). Subsequent builds are fast due to Docker layer caching.
Open the web UI: http://localhost:8000/app
Open the API docs: http://localhost:8000/docs
Configuration
Set environment variables in .env (picked up automatically by docker compose):
# Minimum — set at least one provider key
ANTHROPIC_API_KEY=sk-ant-api03-xxx
DEFAULT_PROVIDER=anthropic
DEFAULT_MODEL=claude-sonnet-4-20250514
# Optional overrides (defaults shown)
DEFAULT_ITERATIONS=3
PORT=8000
LOG_LEVEL=info
CORS_ORIGINS=*
SIMILARITY_THRESHOLD=0.85
# Fast model for extraction/enrichment (Anthropic only, optional)
FAST_MODEL=claude-haiku-4-5-20251001
# Shared secret to protect the Settings PATCH /config endpoint (optional)
CONFIG_SECRET=your-secret-here
All variables are documented in .env.example.
Build arguments
| Argument | Default | Purpose |
|---|---|---|
CONTEXT_LINK_VERSION |
1.0.0 |
context-link release to download from GitHub releases |
EMBEDDING_MODEL |
BAAI/bge-small-en-v1.5 |
fastembed model to pre-bake into the image |
# Pin to a specific context-link release
CONTEXT_LINK_VERSION=1.0.0 docker compose build
# Build with a different embedding model
EMBEDDING_MODEL=BAAI/bge-base-en-v1.5 docker compose build
Building without context-link (offline / no Go toolchain)
If you can't reach GitHub at build time, remove the Go stage:
- Comment out or delete the
context-link-builderstage inDockerfile. - Remove the
COPY --from=context-link-builderline in thefinalstage. - Mount your own pre-built binary at runtime:
# docker-compose.yml — uncomment this volume entry
volumes:
- ./data:/app/data
- /path/to/context-link:/app/bin/context-link:ro
The app works without the binary — the --code flag just logs a warning and runs without code context.
Using the CLI inside the container
# Run a threat model against a file already inside the container
docker compose exec app paranoid run /app/examples/stride-example-api-gateway.md
# Mount a local file and run it
docker run --rm \
-v $(pwd)/my-system.md:/workspace/system.md \
-v $(pwd)/data:/app/data \
-e ANTHROPIC_API_KEY=sk-ant-xxx \
paranoid-app-1 \
paranoid run /workspace/system.md --format markdown -o /app/data/out.md
Persistent data
The SQLite database is stored at /app/data/paranoid.db inside the container, bind-mounted to ./data/ on the host. This directory persists threat models across container restarts and image upgrades.
Output Formats
JSON Simple (default, ~2-3 KB)
Lightweight threat summaries for CI/CD dashboards and quick reviews.
{
"execution": {
"total_threats": 17,
"iterations_completed": 2,
"duration_seconds": 115.0
},
"threats": [
{
"name": "JWT Token Forgery",
"category": "Spoofing",
"target": "API Gateway",
"impact": "Complete authentication bypass",
"likelihood": "Medium",
"mitigation_count": 3
}
]
}
JSON Full (~45 KB)
Complete Pydantic models with DREAD scores and full pipeline event audit trail. Suitable for detailed analysis, archival, and integration with other tools.
paranoid run system.md --format full -o complete.json
Markdown (~4–15 KB)
Human-readable reports for PRs, Confluence, Notion, and security review documents. Contains a summary table, per-category threat sections, DREAD scores, and tagged mitigations.
paranoid run system.md --format markdown -o threats.md
Output structure:
# Threat Model: my-system
**Framework:** STRIDE | **Model ID:** `a1b2c3d4` | **Generated:** 2026-04-02
## Summary
| # | Threat | Category | Target | Likelihood | DREAD |
...
## Threats
### Tampering
#### 1. SQL Injection
**Target:** Database | **Likelihood:** High | **Impact:** Data breach
**DREAD:** 7.5/10 *(D:8 R:7 E:8 A:6 Di:7)*
> An attacker exploits unparameterized queries...
**Mitigations:**
- [P] Use parameterized queries / prepared statements
- [D] Enable query anomaly logging
Pass include_header=False when calling export_markdown() directly to omit the H1 heading and metadata block for embedding into existing documents.
PDF (~50–200 KB)
Structured PDF reports for security review sign-off, archival, and sharing with stakeholders who don't use Markdown. Contains the same content as the Markdown export: title, metadata, summary table, per-category threat sections, DREAD scores, and tagged mitigations. Produced via reportlab — no external binaries required.
paranoid run system.md --format pdf -o report.pdf
paranoid models export a1b2c3d4 --format pdf -o report.pdf
SARIF (GitHub Security Integration)
SARIF 2.1.0 format for GitHub Security tab, GitLab, VS Code, and Azure DevOps:
paranoid run system.md --format sarif -o threats.sarif
GitHub Actions Integration:
Use the official Paranoid action for zero-config SARIF upload to the GitHub Security tab:
name: Threat Model
on: [push, pull_request]
permissions:
security-events: write
contents: read
jobs:
threat-model:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Paranoid threat modeling
id: paranoid
uses: theAstiv/paranoid@v1.4.0
with:
description-file: docs/system-description.md
provider: anthropic
api-key: ${{ secrets.ANTHROPIC_API_KEY }}
framework: STRIDE
iterations: 3
- name: Upload SARIF to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: ${{ steps.paranoid.outputs.sarif-file }}
Action inputs:
| Input | Default | Description |
|---|---|---|
description-file |
— | Path to system description (.md / .txt), relative to repo root |
provider |
anthropic |
anthropic, openai, or ollama |
api-key |
— | Provider API key; omit for Ollama |
model |
provider default | Model override (e.g. claude-sonnet-4-5, gpt-4o) |
framework |
STRIDE |
STRIDE or MAESTRO |
iterations |
3 |
Pipeline iterations (1–15) |
sarif-output |
paranoid-results.sarif |
SARIF output path |
strict |
false |
Exit 2 on error-severity description gaps |
fail-on-findings |
false |
Fail the step if any threats are found |
Code-as-Input (--code)
Ground threats in actual source code using the context-link MCP binary. When --code is provided, Paranoid extracts a semantically relevant slice of the codebase and threads it through every pipeline node.
paranoid run system.md --code /path/to/repo
paranoid run system.md --code /path/to/repo --iterations 5
paranoid run system.md --diagram arch.png --code /path/to/repo # combined
How it works:
-
Three-tier extraction funnel (50KB budget, ~12.5K tokens):
- Semantic search:
semantic_search_symbolsfinds symbols relevant to the threat model description - Code body extraction:
get_code_by_symbolfetches full source for top results - File skeletons:
get_file_skeletonfills remaining budget with structural outlines
- Semantic search:
-
Code summary step:
_deterministic_code_summary()extracts a focused ~2KBCodeSummary(tech stack, entry points, auth patterns, data stores, security observations) fromCodeContextusing file-extension mapping, import scanning, and keyword matching — no LLM call required.summarize_code()(LLM-backed) is available as an opt-in upgrade path when pattern matching isn't sufficient. -
Full pipeline threading: The
CodeSummaryis passed to all downstream nodes —extract_assets,extract_flows,generate_threats, andgap_analysis— so threats reference actual implementation details. -
Deterministic extraction:
_deterministic_code_summary()covers tech stack from file extensions, HTTP routes from decorator patterns, auth/DB/HTTP-client keywords, and security anti-patterns (eval(),pickle.load,shell=True, SQL string concatenation). The pipeline never silently drops code context.
Installing context-link:
context-link is a standalone Go binary that indexes your repository and serves an MCP tool interface over stdio. Get it from github.com/context-link-mcp/context-link:
# Option 1: pre-built binary (recommended — no Go toolchain required)
# Download the binary for your platform from the GitHub Releases page:
# https://github.com/context-link-mcp/context-link/releases/latest
# Then place it at bin/context-link or add it to PATH.
# Option 2: build from source (requires Go 1.22+)
git clone https://github.com/context-link-mcp/context-link
cd context-link
CGO_ENABLED=1 go build -o context-link ./cmd/context-link
# Move the resulting binary to bin/context-link or PATH
Requirements:
- context-link binary at
bin/context-link(relative to working directory), onPATH, or at the path set byCONTEXT_LINK_BINARY - Binary discovery order: explicit
CONTEXT_LINK_BINARYenv var →./bin/context-link→shutil.which("context-link") - If the binary is not found, Paranoid logs a warning and continues without code context
Error handling: Every MCP failure degrades gracefully — binary not found, subprocess crash, tool call error, and index timeout all produce a warning and allow the pipeline to continue with text-only input.
Code Sources (Web UI)
The web UI lets you clone and index Git repositories directly from the browser, then select a source when creating a new threat model — no CLI or Docker volume required.
Adding a code source
- Navigate to Sources in the top navigation.
- Click Add source and fill in:
- Git URL —
https://github.com/owner/repo.git(GitHub, GitLab, Bitbucket, or hosts added viaADDITIONAL_GIT_HOSTS) - Name — a short label shown in the wizard
- Branch / tag / commit (optional) — leave blank to track the default branch; enter a commit SHA to pin to a specific revision
- Personal access token (optional) — for private repos; stored Fernet-encrypted at rest
- Git URL —
- Click Add & clone. The source card shows live progress:
queued → cloning → indexing → ready.
Once a source is ready, select it in the Code Source step of the New Model wizard. The pipeline extracts a semantically relevant slice of the codebase and threads it through every threat-generation step.
Security model for stored credentials
- PATs are Fernet-encrypted (AES-128-CBC + HMAC-SHA256) before being written to SQLite.
- Key derivation:
CONFIG_SECRETenv var → PBKDF2-HMAC-SHA256 (100k iterations); falls back to a random 32-byte file key atdata/.source_key(mode 0600). - The raw PAT is never logged, never included in SSE events, and never returned by any API endpoint (
has_pat: boolonly). - Git clones use hardened flags:
protocol.file.allow=never(blocks submodulefile://transport),core.symlinks=false,GIT_TERMINAL_PROMPT=0.
Requirements
- RAM: 4 GB minimum. The fastembed ONNX embedding model (~130 MB resident), context-link indexer, and a git clone of a large monorepo can peak at 2–3 GB together; leave headroom for the LLM pipeline.
- Disk: clone directories live at
data/sources/<id>/inside the mounted data volume. - Network: HTTPS-only git URLs; host allowlist is
github.com,gitlab.com,bitbucket.orgby default.
# Allow additional private hosts (exact hostname match, no wildcards)
ADDITIONAL_GIT_HOSTS=git.company.com,git.internal.net docker compose up
Image-as-Input (--diagram)
Supply an architecture diagram alongside your text description. Paranoid passes it to every pipeline node for richer threat coverage.
# PNG or JPG via vision API
paranoid run system.md --diagram architecture.png
paranoid run system.md --diagram architecture.jpg
# Mermaid (.mmd) as text — works with all providers
paranoid run system.md --diagram flow.mmd
# Combined with code context
paranoid run system.md --diagram arch.png --code /path/to/repo
Supported formats:
| Format | Mechanism | Size Limit |
|---|---|---|
| PNG | Vision content block (base64) | 5MB |
| JPG/JPEG | Vision content block (base64) | 5MB |
Mermaid .mmd |
<architecture_diagram> XML tag (text) |
100KB |
Provider support:
| Provider | PNG/JPG | Mermaid |
|---|---|---|
| Anthropic (all models) | Full support | Full support |
OpenAI gpt-4o, gpt-4o-mini |
Full support | Full support |
| OpenAI other models | Not supported (use gpt-4o) | Full support |
| Ollama | Logs warning, continues without image | Full support |
How it works:
- PNG/JPG: The image is base64-encoded and passed as a vision content block in the provider's native format (Anthropic
imagecontent block; OpenAIimage_urldata URI). Each prompt's<architecture_diagram>instruction is replaced with a vision-specific directive. - Mermaid: The
.mmdfile is read as UTF-8 text and injected as<architecture_diagram>XML in the prompt. All providers parse Mermaid syntax natively — no rendering required. - Pipeline threading:
DiagramDatathreads through all 5 pipeline nodes:summarize,extract_assets,extract_flows,generate_threats, andgap_analysis.
Structured Input Templates
Paranoid supports rich XML-tagged templates for better context and assumption enforcement. See Input-template.md for the full template reference and examples/ for working examples.
STRIDE Template (traditional systems): Component description with technology stack, interfaces, data handling, and 6 structured assumption sections.
MAESTRO Template (AI/ML systems): Extended component description with mission alignment, agent profile, and 9 structured assumption sections.
Model Configuration
Use Claude Sonnet (or newer) for reliable structured output generation.
| Model | Status | Notes |
|---|---|---|
claude-sonnet-4-20250514 |
Recommended | Validated end-to-end, reliable for production |
claude-haiku-4-5-20251001 |
Not recommended as main model | Fails with JSON parsing errors on complex threat outputs; recommended as FAST_MODEL for extraction/enrichment steps |
gpt-4o |
Supported | Works well, also supports vision (--diagram) |
| Ollama (Llama 3 70B+) | Supported | Fully local, no external API calls |
Architecture
- Backend: FastAPI + SQLite + sqlite-vec (loaded via
sqlite_vec.loadable_path()— works on Windows without manual DLL installation) - Frontend: Svelte + Tailwind SPA with svelte-spa-router — implemented (see
frontend/); available when running the web server (uvicorn backend.main:app) - LLM Providers: Anthropic / OpenAI / Ollama (protocol-based, swappable)
- Pipeline: Plain async functions (no LangChain, no LangGraph)
- Embeddings: Local via fastembed (ONNX, BAAI/bge-small-en-v1.5)
- Models: Pydantic v2 for all data validation
- Frameworks: STRIDE (traditional) + MAESTRO (AI/ML security)
- Code context: context-link MCP binary (Go) +
MCPCodeExtractorasync context manager - Image input:
backend/image/package —encoder.py(PNG/JPG base64),mermaid.py(text load),validation.py(size/format)
Python API:
from backend.pipeline.runner import run_pipeline_for_model
from backend.providers.anthropic import AnthropicProvider
from backend.models.enums import Framework
provider = AnthropicProvider(model="claude-sonnet-4-20250514", api_key="your-key")
async for event in run_pipeline_for_model(
model_id="web-app-001",
description="E-commerce web application...",
framework=Framework.STRIDE,
provider=provider,
max_iterations=3,
):
print(f"[{event.step}] {event.message}")
Testing
# Run unit/integration tests (no API key required)
pytest tests/ -v
# Run end-to-end pipeline test (requires ANTHROPIC_API_KEY)
pytest tests/test_pipeline_e2e.py -v
# Validate structured input parser (no API key required)
python examples/test_structured_input.py
# Lint
ruff check backend/ cli/
ruff format backend/ cli/
Troubleshooting
Authentication errors:
- Check your API key is correct in
.envor~/.paranoid/config.json - For Anthropic, ensure billing is set up and key starts with
sk-ant-api03-
Module not found:
pip install -e . # or: pip install paranoid-cli
Ollama connection refused:
ollama serve # start Ollama first, then run paranoid
--code flag: context-link binary not found:
Install context-link from github.com/context-link-mcp/context-link (pre-built binaries on the Releases page), then make it available to Paranoid:
# Option 1: set env var pointing to the binary
export CONTEXT_LINK_BINARY=/path/to/context-link
# Option 2: place binary at bin/context-link relative to working directory
# Option 3: add context-link to PATH
If the binary is missing, Paranoid logs a warning and continues without code context.
sqlite-vec not loading (Windows "module not found"):
This was a known issue on Windows where a bare vec0 extension name was used. It is fixed in the current release — the extension is now loaded via the absolute path from the bundled sqlite-vec Python package (sqlite_vec.loadable_path()), which resolves correctly on all platforms. No manual DLL installation required; pip install paranoid-cli includes everything.
--diagram with OpenAI and vision errors:
Only gpt-4o and gpt-4o-mini support JSON structured output together with vision. Other OpenAI models that support vision do not support JSON mode simultaneously. Switch to gpt-4o or use Anthropic.
--diagram with Ollama:
Ollama does not support vision for most models. Paranoid logs a warning and continues without the image. Use --diagram flow.mmd (Mermaid text) instead — all providers support Mermaid.
macOS binary "developer cannot be verified":
xattr -d com.apple.quarantine paranoid-macos-arm64
Windows "Windows protected your PC": Click "More info" then "Run anyway", or add an exception in Windows Defender.
Platform Support
| Platform | PyPI | Docker | Binary |
|---|---|---|---|
| Ubuntu 20.04+ | Yes | Yes | Yes |
| Debian 11+ | Yes | Yes | Yes |
| RHEL 8+ | Yes | Yes | Yes |
| macOS 11+ (Intel) | Yes | Yes | No |
| macOS 11+ (ARM64) | Yes | Yes | Yes |
| Windows 10+ | Yes | Yes | Yes |
| WSL2 | Yes | Yes | Yes |
Documentation
- CHANGELOG.md — Release history
- Input-template.md — Structured input template reference
- examples/ — Working STRIDE and MAESTRO examples
- RELEASE.md — Maintainer release checklist
Developer docs:
- .claude/rules/CLAUDE.md — Project structure and conventions
- .claude/rules/RULES.md — Coding standards
- .claude/rules/tech-decision-rationale.md — Architecture decisions
Development Status
v1.5.0 — Docker UX release. Non-technical users can now open the web app, paste an API key, link a Git repo, and get a threat model — no terminal required.
Completed: Core pipeline (8 nodes, iteration logic, SSE, dual framework), LLM providers (Anthropic/OpenAI/Ollama), STRIDE + MAESTRO prompts, structured input templates, JSON + SARIF + Markdown + PDF export, DREAD scoring, CLI with config wizard, code-as-input via context-link MCP (--code CLI and code sources web UI), image-as-input via vision API and Mermaid text (--diagram), deterministic rule engine (362 curated patterns across 16 seed files, RAG retrieval), provider offline fallback (rule-engine-only mode), Anthropic prompt caching (~20–30% token reduction), full SQLite persistence (every run saved with assets/flows/threats/DREAD), full CRUD for all 12 schema entities, paranoid models list/show/export/delete/prune commands, --provider/--model run-time overrides, REST API (26+ routes with SSE and full CRUD), Svelte + Tailwind frontend (all pages and components implemented), Docker Compose deployment (3-stage build: Go + Node + Python, web UI served at /app), packaging and release automation, fast provider routing (FAST_MODEL for extraction/enrichment), --enrich CLI flag (attack trees + Gherkin test cases per threat), enrichment included in Markdown/PDF exports, encrypted API key + PAT storage (Fernet), first-run redirect + Settings UI overhaul, provider liveness probe, git clone + index pipeline with SSE progress, CSRF protection (ALLOWED_ORIGINS).
Future (v2.0+): Multi-user collaboration.
License
Apache 2.0
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
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 paranoid_cli-1.5.0.tar.gz.
File metadata
- Download URL: paranoid_cli-1.5.0.tar.gz
- Upload date:
- Size: 302.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 |
6ca9b7b3a7063b50242b39290d8a453fa7521ac5556ae8720296b1809233d7a2
|
|
| MD5 |
7862f2cf1b34948073d6070c0ad2be43
|
|
| BLAKE2b-256 |
bdfda777e00a1ca5cc357e7f1b9241259335b11740040ae9b7bd7613f32d393f
|
Provenance
The following attestation bundles were made for paranoid_cli-1.5.0.tar.gz:
Publisher:
release.yml on theAstiv/paranoid
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
paranoid_cli-1.5.0.tar.gz -
Subject digest:
6ca9b7b3a7063b50242b39290d8a453fa7521ac5556ae8720296b1809233d7a2 - Sigstore transparency entry: 1340528730
- Sigstore integration time:
-
Permalink:
theAstiv/paranoid@bc1dd4af3700abae4e658b3fc090ea02057d0e01 -
Branch / Tag:
refs/tags/v1.5.0 - Owner: https://github.com/theAstiv
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bc1dd4af3700abae4e658b3fc090ea02057d0e01 -
Trigger Event:
push
-
Statement type:
File details
Details for the file paranoid_cli-1.5.0-py3-none-any.whl.
File metadata
- Download URL: paranoid_cli-1.5.0-py3-none-any.whl
- Upload date:
- Size: 298.0 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 |
f5893f8c6269030bde5c94db913d0842e0551f7080f4ab83b4717039b9192d47
|
|
| MD5 |
6fe291115876ab3eb324dc319ef4e8f8
|
|
| BLAKE2b-256 |
ebe73f0635aafe9bc4ef6dae16acebb7f479d51c7fbc7a683f3c3f784b664931
|
Provenance
The following attestation bundles were made for paranoid_cli-1.5.0-py3-none-any.whl:
Publisher:
release.yml on theAstiv/paranoid
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
paranoid_cli-1.5.0-py3-none-any.whl -
Subject digest:
f5893f8c6269030bde5c94db913d0842e0551f7080f4ab83b4717039b9192d47 - Sigstore transparency entry: 1340528732
- Sigstore integration time:
-
Permalink:
theAstiv/paranoid@bc1dd4af3700abae4e658b3fc090ea02057d0e01 -
Branch / Tag:
refs/tags/v1.5.0 - Owner: https://github.com/theAstiv
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bc1dd4af3700abae4e658b3fc090ea02057d0e01 -
Trigger Event:
push
-
Statement type: