Local-first Cyber Threat Intelligence platform for security analysts.
Snowl automates the collection, extraction, enrichment, and reporting of threat intelligence from RSS feeds. It combines LLM-powered structured extraction with a Zettelkasten knowledge graph for campaign detection and CTI framework analysis.
| Requirement | Version | Check |
|---|---|---|
| Python | 3.10+ | python3 --version |
| Docker | 20+ | docker --version |
| Docker Compose | v2+ | docker compose version |
| Git | any | git --version |
| OpenRouter API Key | - | openrouter.ai |
git clone https://github.com/bitsalv/snowl.git
cd snowlmake initThis creates a virtual environment (.venv/), installs all Python dependencies from requirements.txt, copies env.template to .env, and creates the snowl/data/ and snowl/logs/ directories.
If make is not available:
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip setuptools wheel
pip install -r requirements.txt
cp env.template .env
mkdir -p snowl/data snowl/logsEdit the .env file at the project root:
nano .envRequired settings:
# REQUIRED - Get your key at https://openrouter.ai/
OPENROUTER_API_KEY=sk-or-v1-your-key-here
OPENROUTER_MODEL=anthropic/claude-3.5-sonnetAll other settings have working defaults. See the full env.template for optional configuration (MCP endpoints, VirusTotal API key, PDF export, etc.).
make dbOr manually:
source .venv/bin/activate
python snowl/src/db/migrate.pyThis creates the SQLite database at snowl/data/snowl.db with all required tables, indexes, and FTS5 full-text search.
Important: You must cd into the TT-RSS directory first so Docker Compose can find the .env file.
First, review and configure the TT-RSS environment:
nano snowl/docker/tt-rss/.env# TT-RSS Docker Configuration
TTRSS_DB_HOST=db
TTRSS_DB_PORT=5432
TTRSS_DB_USER=ttrss
TTRSS_DB_PASS=ttrss_secure_password_changeme # Change this!
TTRSS_DB_NAME=ttrss
TTRSS_PLUGINS=auth_internal,snowl_bridge
ADMIN_USER_PASS=password # Change this!
HTTP_PORT=8280Then start the containers:
cd snowl/docker/tt-rss
docker compose up -d
cd ../../..Do NOT use
docker compose -f snowl/docker/tt-rss/docker-compose.yml up -dfrom the project root. Docker Compose resolves the.envfile relative to the current working directory, not the docker-compose.yml location, so the TT-RSS environment variables (TTRSS_DB_USER,TTRSS_DB_PASS, etc.) will not be found.
Wait for the containers to be healthy:
docker compose -f snowl/docker/tt-rss/docker-compose.yml psYou should see 4 containers running: db, app, web-nginx, updater.
TT-RSS will be available at http://localhost:8280
Default credentials:
- Username:
admin - Password:
password(change immediately!)
# Install the snowl_bridge plugin and auto-labeling trigger
make ttrss-install-trigger
# Install CTI framework content filters (MITRE, Kill Chain, Diamond Model)
make ttrss-install-filtersmake runOr manually:
source .venv/bin/activate
streamlit run snowl/src/Home.pySnowl runs at http://localhost:8501
MCP servers provide AI-powered enrichment (CVE lookup, MITRE ATT&CK, vulnerability search, etc.). Snowl works without them but with reduced functionality.
cd snowl/docker/mcp
docker compose build --no-cache # First time only (downloads repos, compiles)
docker compose up -d
cd ../../..Then configure the endpoints in your .env:
MCP_CVE_SEARCH_ENDPOINT=http://localhost:8081
MCP_OSV_ENDPOINT=http://localhost:8082
MCP_NIST_ENDPOINT=http://localhost:8083
MCP_ATTACK_ENDPOINT=http://localhost:8084
MCP_SQLITE_EXPLORER_ENDPOINT=http://localhost:8085
MCP_LOCAL_RAG_ENDPOINT=http://localhost:8086
MCP_MARKMAP_ENDPOINT=http://localhost:8087| MCP Server | Port | Source | Description |
|---|---|---|---|
| cve-search | 8081 | CIRCL.lu | CVE search and vendor/product lookup |
| osv | 8082 | Google OSV | Open source vulnerability database |
| nist-nvd | 8083 | NIST NVD | National Vulnerability Database, KEV catalog |
| mitre-attack | 8084 | MITRE ATT&CK | Tactics, techniques, groups, software |
| sqlite-explorer | 8085 | Local | Direct SQL queries on Snowl database |
| local-rag | 8086 | Local | Semantic search with vector embeddings |
| markmap | 8087 | Local | Mind map generation from Markdown |
# Everything in order (copy-paste)
git clone https://github.com/bitsalv/snowl.git
cd snowl
make init
nano .env # Add OPENROUTER_API_KEY
make db
cd snowl/docker/tt-rss && docker compose up -d && cd ../../..
make ttrss-install-trigger
make ttrss-install-filters
make run # http://localhost:8501You ran docker compose from the wrong directory. The .env file must be in the same directory where you run docker compose:
# Wrong
docker compose -f snowl/docker/tt-rss/docker-compose.yml up -d
# Correct
cd snowl/docker/tt-rss
docker compose up -dVirtual environment not activated:
source .venv/bin/activate
make runCheck if ports are available:
# TT-RSS uses port 8280 (web) and 5433 (PostgreSQL)
lsof -i :8280
lsof -i :5433MCP servers clone from GitHub during build. Ensure internet access and try:
cd snowl/docker/mcp
docker compose build --no-cache| Feature | Description |
|---|---|
| Structured LLM Extraction | Single-pass extraction of entities, IOCs, TTPs, and CTI categories via OpenRouter |
| 11 CTI Categories | From CVEs to Geopolitical threats, with auto-classification |
| IOC Extraction | IPs, domains, hashes, CVEs, MITRE ATT&CK TTPs |
| Automatic Enrichment | NIST NVD + MITRE ATT&CK mapping via MCP servers |
| Semantic Search | TF-IDF based article similarity |
| Feature | Description |
|---|---|
| Atomic Notes | One note per intelligence entity, auto-generated from analysis |
| Auto-Backlinks | Bidirectional links between related notes |
| Hierarchical Tags | Diamond Model, Kill Chain, severity, temporal tags |
| Campaign Detection | Cluster related articles via shared entities and relationships |
| Framework | Implementation |
|---|---|
| Diamond Model | Automatic 4-vertex identification (Adversary, Capability, Infrastructure, Victim) |
| Cyber Kill Chain | MITRE TTPs mapped to 7 Kill Chain phases |
| MITRE ATT&CK | Tactic and technique extraction with enrichment |
| Feature | Description |
|---|---|
| 5 Report Types | Executive, Technical, Threat Landscape, IOC, Campaign |
| PDF Export | Professional reports via WeasyPrint + Jinja2 |
| STIX 2.1 Export | Standards-compliant threat intelligence bundles |
| CSV Export | Filtered data export |
| Feature | Description |
|---|---|
| CTI Assistant | LLM-powered chatbot with MCP tool integration and session persistence |
| Interactive Dashboard | Plotly charts for framework analytics and KPIs |
| TT-RSS Integration | Full Tiny Tiny RSS integration with custom plugin, theme, and content filters |
+------------------+
| TT-RSS |
| RSS aggregation |
| (Docker stack) |
+--------+---------+
|
snowl_bridge API
|
+----------------------------v----------------------------+
| Snowl |
| |
| Ingest ─> Extract ─> Enrich ─> Classify ─> Store |
| │ │ │ │ │ |
| RSS/API LLM pass NVD/ATT&CK 11 cats SQLite |
| IOC regex MCP servers FTS5 |
| |
| Pipeline output: |
| ├── Zettelkasten notes (atomic, backlinked) |
| ├── Tags (Diamond Model, Kill Chain, severity) |
| ├── Reports (PDF, 5 types) |
| └── Export (STIX 2.1, CSV) |
| |
| Interactive: |
| ├── Dashboard (Plotly analytics) |
| ├── Assistant (LLM + MCP tools) |
| └── IOC search & validation |
+----------------------------------------------------------+
| Page | Description |
|---|---|
| Home | Platform status, pending articles, pipeline trigger |
| Analytics | KPI dashboard with timeline, category distribution, top threats |
| Assistant | CTI chatbot with MCP tool integration |
| Notes | Zettelkasten knowledge base with backlinks and graph |
| Reports | Generate and preview CTI reports |
| Archive | Browse and manage generated reports |
| IOC | Search and validate indicators by type |
| Export | CSV and STIX 2.1 export with filters |
| Settings | API keys, model selection, connection tests |
Snowl uses Tiny Tiny RSS (GPL-3.0) as its feed aggregation backend.
| Component | Description |
|---|---|
| snowl_bridge plugin | Exposes articles to Snowl via JSON API |
| Custom theme | Dark theme optimized for CTI triage |
| Content filters | Auto-highlight MITRE ATT&CK, Kill Chain, Diamond Model terms |
| Auto-labeling trigger | PostgreSQL trigger assigns "Pending Analysis" to new articles |
| Docker Compose | Pre-configured TT-RSS + PostgreSQL stack |
License: The snowl_bridge plugin (AGPL-3.0) runs inside TT-RSS (GPL-3.0) -- these licenses are compatible. The main Snowl platform communicates with TT-RSS via HTTP API as separate programs.
All settings are in the .env file (copied from env.template):
# Required
OPENROUTER_API_KEY=sk-or-v1-...
OPENROUTER_MODEL=anthropic/claude-3.5-sonnet
# Database
DB_PATH=data/snowl.db
# Features
USE_LLM_CLASSIFY=true
USE_EMBEDDINGS=false
ENABLE_PDF=true
# MCP Servers (optional, see Step 8)
MCP_CVE_SEARCH_ENDPOINT=
MCP_NIST_ENDPOINT=
MCP_ATTACK_ENDPOINT=
# Logging
LOG_LEVEL=INFO53 curated CTI feeds ship in snowl/data/default_feeds.yaml across categories: CVE, Malware, Threat Intel, CERT, Cloud, ICS, and more. Add custom feeds via the Settings page or by editing the YAML.
make help # All available commands
make test # Run test suite
make test-cov # Tests with coverage report
make format # Format code (black)
make lint # Run linters
make clean # Clean cachessnowl/
├── src/
│ ├── Home.py # Streamlit entry point
│ ├── config.py # Pydantic config + .env
│ ├── pages/ # 8 Streamlit pages
│ ├── pipeline/ # LLM analysis + Zettelkasten
│ ├── ingest/ # RSS/TT-RSS ingestion
│ ├── extract/ # LLM + IOC extraction
│ ├── enrich/ # NVD, ATT&CK, MCP enrichment
│ ├── export/ # CSV, STIX 2.1, PDF
│ ├── reports/ # Report generation (5 types)
│ ├── chat/ # CTI Assistant (LLM + MCP)
│ ├── search/ # TF-IDF semantic search
│ ├── zettelkasten/ # Knowledge graph operations
│ ├── integrations/ # TT-RSS client (5 modules)
│ ├── db/ # SQLite + APSW + FTS5 + migrations
│ └── ui/ # Streamlit components + theming
├── data/
│ ├── snowl.db # SQLite database
│ └── default_feeds.yaml # 53 curated CTI feeds
├── docker/
│ ├── tt-rss/ # TT-RSS Docker stack + plugin
│ │ ├── docker-compose.yml
│ │ ├── .env # TT-RSS environment variables
│ │ └── config.d/ # TT-RSS PHP config overrides
│ └── mcp/ # MCP server containers
│ ├── docker-compose.yml
│ ├── dockerfiles/ # Dockerfiles for each MCP server
│ └── repos/ # Cloned MCP server repositories
├── tests/ # Test suite
└── config/ # Configuration files
GNU Affero General Public License v3.0 (AGPL-3.0) -- see LICENSE.
Built for security analysts, by security analysts.
