Skip to content

MISP Integration

zach115th edited this page Jul 31, 2026 · 2 revisions

MISP Integration

Overview

IRIS-NG ships two complementary MISP integration features:

  1. Goal #1 — Native MISP sync module (IrisMISPSyncModule): bidirectional sync of cases and IOCs to MISP events and attributes
  2. Goal #2 — MISP nomenclature alignment: every IOC type maps to a canonical MISP attribute type via IocType.type_taxonomy

A third, separate module publishes correlation results rather than individual cases: IrisMISPCluster pushes a cross-case IOC cluster to MISP as a single campaign event, on demand and one-directionally. See MISP Cluster Publishing. It shares this module's REST client, so the tag-search fix below applies to both.

Goal #1 — IrisMISPSyncModule

What it syncs

iris-ng event MISP result
Case created New MISP event created; link stored in misp_event_link
Case updated MISP event info updated
IOC created on case New MISP attribute created on the event; link stored in misp_attribute_link
IOC updated MISP attribute updated

The IOC's TLP drives the MISP attribute distribution and applies the matching tlp:<level> tag on the attribute.

Schema additions

Table Purpose
misp_event_link Maps case_idmisp_event_uuid
misp_attribute_link Maps ioc_idmisp_attribute_uuid

Module configuration

Navigate to /manage/modulesIrisMISPSync → Configure:

Setting Description
MISP URL Base URL of your MISP instance
MISP API key Authkey from MISP /auth_keys
Verify TLS Uncheck for self-signed certificates (lab/internal MISP)
AI API key For the AI type resolver fallback (Goal #2)

No restart required when changing module settings — parameters are read per-call.

TLS

If your MISP uses a self-signed certificate, disable Verify TLS in the module config. This skips MITM protection — acceptable for internal/lab use. For stricter environments, add the MISP CA to the app and worker container trust stores.

Troubleshooting

Symptom Cause Fix
(psycopg2.DatabaseError) PGRES_TUPLES_OK on hook tasks Celery fork-safety Already fixed via NullPool in __init__.py — do not add db.session.remove() shims
NotImplementedError in _indexes_for_keys before module runs app/worker code skew after upgrade Run up --build --force-recreate
SSLCertVerificationError: self-signed certificate TLS Uncheck Verify TLS in module config
(406) PRECONDITION_FAILED - inequivalent arg 'x-max-priority' on case import Wrong celery queue-priority config Fixed in configuration.pyai_queue only; celery default queue is bare

Developer helpers

# Configure module via API (reads from .env)
docker exec iriswebapp_app python /iriswebapp/scripts/iris_misp_sync_dev.py configure

# Smoke test: create a case + IOC, verify MISP sync
docker exec iriswebapp_app python /iriswebapp/scripts/iris_misp_sync_dev.py smoke-test

# Re-sync a single IOC (bypasses celery, recovers dropped syncs)
docker exec iriswebapp_app python /iriswebapp/scripts/iris_misp_sync_dev.py resync-ioc --ioc-id <id>

# Validate MISP sync state
docker exec iriswebapp_app python /iriswebapp/scripts/validate_misp_sync.py

MISP tag search API note

GET /tags/search/<term> silently returns [] for any tag name containing : — which is every MISP taxonomy tag (tlp:green, circl:incident-classification="…", etc.).

Always use POST /tags/index with body {"searchall": term} when looking up a tag by name.

Goal #2 — MISP nomenclature alignment

IocType.type_taxonomy column

Every row in the ioc_type table carries a type_taxonomy column mapping it to the canonical MISP attribute type. This is populated at app startup from the bundled MISP catalog (source/app/resources/misp.attribute_types.json, 193 types).

AI fallback for unmatched types

Three IRIS-local types have no clean MISP match (account, file-path, ip-any). For these, source/iris_misp_sync_module/ai_type_resolver.py calls LM Studio (gpt-oss-20b) at confidence ≥ 0.70 to resolve them.

# Test the AI fallback resolver
docker exec iriswebapp_app python /iriswebapp/scripts/iris_misp_sync_dev.py test-ai-fallback

MISP catalog in the UI

The bundled MISP taxonomy + galaxy catalog powers tag autocomplete across every object modal in the UI (cases, IOCs, assets, tasks, events, evidence).

The catalog lazy-loads once on first /manage/tags/suggest call (~52 MB in-memory). Each search is a linear scan with early-exit at limit 25 (~30-50 ms per call).

Refreshing the catalog

# Download the latest taxonomies + galaxies from GitHub
docker exec iriswebapp_app python /iriswebapp/scripts/download_misp_tag_bundles.py

Celery fork-safety — load-bearing rule

Celery prefork workers inherit the parent's SQLAlchemy QueuePool and the live psycopg2 connection file descriptors. Concurrent children corrupt each other's protocol state on a shared fd.

The fix is NullPool for worker processes only, configured in source/app/__init__.py keyed on "worker" in sys.argv. Every query opens a fresh connection and closes it on return.

Do not add per-module db.session.remove() at the top of hooks_handler — this detaches ORM objects handed in by task_hook_wrapper and causes DetachedInstanceError.

The task_prerun / worker_process_init session-drop handlers in tasker/tasks.py remain as defense-in-depth but are not the primary fix.

Clone this wiki locally