external/anthropic-cybersecurity-skills/skills/modeling-threats-with-opencti/SKILL.md
Model threat actors, intrusion sets, campaigns, and TTPs as a STIX 2.1 knowledge graph in OpenCTI (Filigran) using the pycti Python client, connectors, and import workers for structured cyber threat intelligence.
npx skillsauth add seikaikyo/dash-skills modeling-threats-with-openctiInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
OpenCTI (Open Cyber Threat Intelligence) is an open-source threat-intelligence platform developed by Filigran that lets analysts store, organize, visualize, and share structured cyber threat intelligence as a knowledge graph. Every object — Threat Actors, Intrusion Sets, Campaigns, Attack Patterns, Malware, Indicators, Observables, Vulnerabilities — is modeled on the STIX 2.1 standard, and the relationships between them (uses, attributed-to, targets, indicates) form a graph that reveals how adversaries operate end to end.
Architecturally, OpenCTI is built from a GraphQL API backed by Elasticsearch/OpenSearch and a graph database, a Redis stream, RabbitMQ message broker, import/export workers, and connectors. Connectors retrieve information from external sources (MITRE ATT&CK, MISP, AlienVault OTX, CISA, abuse.ch, etc.), convert it into STIX 2.1 bundles, and submit those bundles to the platform; workers then ingest the bundles into the graph. The official Python client, pycti (OpenCTIApiClient), is the programmatic interface analysts use to create entities, build relationships, and push STIX bundles.
This skill follows the official OpenCTI documentation (docs.opencti.io) and the OpenCTI-Platform/client-python (pycti) repository. It maps to MITRE ATT&CK T1589 (Gather Victim Identity Information) as part of the broader CTI analysis lifecycle — OpenCTI is where reconnaissance and adversary tradecraft observed across reporting is consolidated, deduplicated, and modeled so detection and response teams can act on it. The threat context is the volume and fragmentation of modern CTI: hundreds of vendor reports, IOC feeds, and ATT&CK updates that are useless until correlated into a single, queryable adversary picture.
pip install pycti stix2
uses, attributed-to, targets) to form the adversary graphsend_stix2_bundle| ID | Name | Relevance | |----|------|-----------| | T1589 | Gather Victim Identity Information | OpenCTI consolidates reconnaissance and victim/target intelligence observed across reporting into a structured, queryable knowledge graph that supports analysis of adversary targeting. |
Use the official Docker Compose stack. Generate the required tokens/UUIDs and start the platform, workers, and dependencies.
git clone https://github.com/OpenCTI-Platform/docker.git opencti-docker
cd opencti-docker
# Generate required secrets (UUID v4 for tokens, base64 for app secret)
cat > .env <<EOF
[email protected]
OPENCTI_ADMIN_PASSWORD=$(openssl rand -hex 16)
OPENCTI_ADMIN_TOKEN=$(cat /proc/sys/kernel/random/uuid)
OPENCTI_BASE_URL=http://localhost:8080
MINIO_ROOT_USER=$(cat /proc/sys/kernel/random/uuid)
MINIO_ROOT_PASSWORD=$(cat /proc/sys/kernel/random/uuid)
RABBITMQ_DEFAULT_USER=guest
RABBITMQ_DEFAULT_PASS=guest
ELASTIC_MEMORY_SIZE=4G
CONNECTOR_HISTORY_ID=$(cat /proc/sys/kernel/random/uuid)
CONNECTOR_EXPORT_FILE_STIX_ID=$(cat /proc/sys/kernel/random/uuid)
EOF
# Increase vm.max_map_count for Elasticsearch, then start the stack
sudo sysctl -w vm.max_map_count=1048575
docker compose up -d
Access the UI at http://localhost:8080 and log in with the admin credentials from .env.
Create an OpenCTIApiClient instance using your platform URL and API token.
from pycti import OpenCTIApiClient
opencti = OpenCTIApiClient(
"http://localhost:8080",
"YOUR_API_TOKEN", # from Profile > API access, or OPENCTI_ADMIN_TOKEN
)
Create a Threat Actor, an Intrusion Set, a Campaign, and an Attack Pattern. pycti create() calls act as upserts when update=True.
# Threat Actor (group)
actor = opencti.threat_actor_group.create(
name="APT-EXAMPLE",
description="Financially motivated intrusion group tracked in this case.",
threat_actor_types=["crime-syndicate"],
)
# Intrusion Set
intrusion_set = opencti.intrusion_set.create(
name="EXAMPLE-SET",
description="Cluster of activity sharing infrastructure and TTPs.",
)
# Campaign
campaign = opencti.campaign.create(
name="Operation Example 2026",
description="Spearphishing campaign targeting the finance sector.",
)
# Attack Pattern linked to MITRE ATT&CK (x_mitre_id maps to the technique)
technique = opencti.attack_pattern.create(
name="Spearphishing Attachment",
x_mitre_id="T1566.001",
)
Connect the objects with STIX relationships so the graph reflects how the adversary operates.
# Intrusion set attributed to the threat actor
opencti.stix_core_relationship.create(
fromId=intrusion_set["id"],
toId=actor["id"],
relationship_type="attributed-to",
)
# Campaign attributed to the intrusion set
opencti.stix_core_relationship.create(
fromId=campaign["id"],
toId=intrusion_set["id"],
relationship_type="attributed-to",
)
# Intrusion set uses the technique
opencti.stix_core_relationship.create(
fromId=intrusion_set["id"],
toId=technique["id"],
relationship_type="uses",
)
Create an indicator with a STIX pattern and tie it to the intrusion set via an indicates relationship.
from dateutil.parser import parse
date = parse("2026-06-01").strftime("%Y-%m-%dT%H:%M:%SZ")
indicator = opencti.indicator.create(
name="C2 domain for Operation Example",
pattern_type="stix",
pattern="[domain-name:value = 'malicious-c2.example']",
x_opencti_main_observable_type="Domain-Name",
valid_from=date,
)
opencti.stix_core_relationship.create(
fromId=indicator["id"],
toId=intrusion_set["id"],
relationship_type="indicates",
)
For bulk ingestion, build a STIX bundle and submit it with send_stix2_bundle — the recommended bulk-ingest path.
import json
with open("threat_report_bundle.json") as f:
bundle = json.load(f)
opencti.stix2.import_bundle_from_json(
json.dumps(bundle),
update=True,
)
Add connectors to the compose stack so external intelligence (MITRE ATT&CK, MISP) is ingested continuously. Each connector needs its own token.
# Append to docker-compose.yml under services:
connector-mitre:
image: opencti/connector-mitre:latest
environment:
- OPENCTI_URL=http://opencti:8080
- OPENCTI_TOKEN=${CONNECTOR_MITRE_TOKEN}
- CONNECTOR_ID=${CONNECTOR_MITRE_ID}
- CONNECTOR_TYPE=EXTERNAL_IMPORT
- CONNECTOR_NAME=MITRE ATT&CK
- CONNECTOR_SCOPE=tool,report,malware,identity,attack-pattern,intrusion-set,campaign
- MITRE_INTERVAL=7 # days
restart: always
docker compose up -d connector-mitre
Read back the adversary's full picture for reporting and detection engineering.
# Resolve all techniques an intrusion set uses
iset = opencti.intrusion_set.read(filters={
"mode": "and",
"filters": [{"key": "name", "values": ["EXAMPLE-SET"]}],
"filterGroups": [],
})
rels = opencti.stix_core_relationship.list(
fromId=iset["id"],
relationship_type="uses",
)
for r in rels:
print(r["to"]["name"], r["to"].get("x_mitre_id"))
| Tool | Purpose | Source | |------|---------|--------| | OpenCTI Platform | STIX 2.1 threat-intel knowledge graph | https://github.com/OpenCTI-Platform/opencti | | OpenCTI Docker | Reference compose stack | https://github.com/OpenCTI-Platform/docker | | pycti | Official Python client for the GraphQL API | https://github.com/OpenCTI-Platform/client-python | | OpenCTI Connectors | Importers (MITRE, MISP, OTX, CISA, abuse.ch) | https://github.com/OpenCTI-Platform/connectors | | OpenCTI docs | Official documentation | https://docs.opencti.io/latest/ | | STIX 2.1 spec | Underlying data model | https://oasis-open.github.io/cti-documentation/ |
| pycti entity | STIX type | Use |
|--------------|-----------|-----|
| threat_actor_group | threat-actor | Named adversary group |
| intrusion_set | intrusion-set | Clustered activity / tracked set |
| campaign | campaign | Time-bounded operation |
| attack_pattern | attack-pattern | MITRE ATT&CK technique |
| malware | malware | Tooling/implant |
| indicator | indicator | Detection pattern (STIX/Sigma/YARA) |
| vulnerability | vulnerability | CVE |
| stix_core_relationship | relationship | uses, attributed-to, targets, indicates |
attributed-to, uses, indicates) built between objectsimport_bundle_from_jsondevelopment
拋棄式 HTML mockup 比稿:產出 2 到 3 個設計立場不同的變體(密度 / 版式 / 強調軸,不是換色),各附取捨說明,最後給有立場的對比結論。適用:「畫個草圖」「比較 A 版 B 版」「先看方向再做」「給我看幾種做法」。要 production 元件或設計已定案時不適用。
tools
需求不明時的意圖萃取訪談:一次一題、每題附上自己的猜測、聽出「真正想要 vs 覺得應該要」,直到能預測使用者反應(約 95% 信心)才動工。適用:需求缺少對象 / 動機 / 成功標準 / 約束,或使用者點名「訪談我」「先確認一下」「我們確定嗎」。明確自足的指示、純資訊查詢、機械性操作不適用。
development
對非平凡決策啟動新鮮 context 對抗審查(找碴不背書),在修正還便宜的時候抓出錯誤方向。適用:高風險改動(production、資安敏感邏輯、不可逆操作)、不熟的程式碼、要宣稱「這樣是安全的 / 可行的」之前。機械性操作與一行修改不適用。
testing
Reference for writing and editing agent skills well — the vocabulary and principles that make a skill predictable. Consult when authoring, reviewing, or pruning a SKILL.md.