Install
$ agentstack add skill-liberty91ltd-cti-skills-lookup-opencti ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
lookup-opencti
Two-way bridge to an OpenCTI threat-intelligence platform. OpenCTI is a STIX 2.1-native knowledge base: everything in it — indicators, observables, intrusion sets, malware, reports, campaigns — is a STIX entity connected by relationships. Like /lookup-misp, this skill also writes: it can create indicators and observables, label and TLP-mark entities, relate them, and import STIX 2.1 bundles. Treat write commands as deliberate actions; don't use them in autonomous enrichment loops. The delete command is destructive — always confirm with the user before invoking it.
When to invoke
Read:
- An indicator was found by another lookup (VT, OTX, …) — check whether your OpenCTI instance already knows it (
lookup) - An analyst wants the entities, reports, or campaigns your platform holds on an actor, malware family, or CVE (
search,list,get) - You need recent high-score indicators, this quarter's incidents, or everything carrying a given label (
listwith filters) - You want to verify connector health or instance version (
connectors,version)
Write:
- A finished investigation produced indicators that belong in your knowledge base
- A STIX 2.1 bundle written via
/stix-bundleshould be imported as entities - An existing entity needs labels, a TLP marking, a score update, or a relationship to another entity
Do NOT invoke for:
- Bulk reputation enrichment (use VT/OTX/RL first; only push the vetted subset into OpenCTI)
- Scanning or pivoting on raw internet infrastructure — OpenCTI is a curated dataset, not a scanning service. Use Shodan/Censys for that.
- Community sharing — that's MISP's job (
/lookup-misp). OpenCTI is your internal knowledge graph; MISP is the exchange layer. Many teams run both, synced by a connector.
How to invoke
Single Python CLI (stdlib only — no install). Single endpoint: everything is GraphQL against $OPENCTI_URL/graphql with Authorization: Bearer $OPENCTI_TOKEN.
Read operations
# Connectivity + version check
python3 tools/clis/opencti.py version
# Is this IOC known? Checks observables AND indicators in one call
python3 tools/clis/opencti.py lookup 1.2.3.4
python3 tools/clis/opencti.py lookup evil.example.com --limit 10
# Global full-text search across all entity types (actors, malware, reports, ...)
python3 tools/clis/opencti.py search "APT28" --limit 10
# List/filter one entity type. Types: indicators, observables, reports, incidents,
# campaigns, intrusion-sets, malware, attack-patterns, vulnerabilities, sightings
python3 tools/clis/opencti.py list indicators --score-gte 80 --created-after 2026-06-01T00:00:00Z
python3 tools/clis/opencti.py list reports --label apt28 --limit 10
python3 tools/clis/opencti.py list intrusion-sets --order-by modified --order desc
# Full detail + first 25 relationships for one entity (id from lookup/search/list)
python3 tools/clis/opencti.py get
# Connector health (which enrichment/import connectors are registered + active)
python3 tools/clis/opencti.py connectors
list paginates: when the response has has_next_page: true, pass the returned end_cursor back via --after for the next page.
Write operations
# Create an indicator (auto-generates the STIX pattern; creates the underlying
# observable too by default so raw-value lookups will find it)
python3 tools/clis/opencti.py create-indicator \
--value 185.220.101.45 --type ip \
--score 85 --description 'C2 observed 2026-07-01' \
--labels apt28,c2
# Explicit STIX pattern (for anything the --type shorthand doesn't cover)
python3 tools/clis/opencti.py create-indicator \
--pattern "[file:hashes.'SHA-256' = '' AND file:name = 'dropper.exe']" \
--observable-type StixFile --name 'APT28 dropper'
# Create a bare observable (a fact, no detection semantics)
python3 tools/clis/opencti.py create-observable --value 185.220.101.45 --type ip --labels apt28
# Label + TLP-mark an existing entity (labels are auto-created if missing)
python3 tools/clis/opencti.py add-label apt28 c2
python3 tools/clis/opencti.py add-marking TLP:AMBER
# Update a field (name | description | score | confidence)
python3 tools/clis/opencti.py update --field score --value 95
# Relate two entities with a STIX relationship (indicates, uses, targets, ...)
python3 tools/clis/opencti.py create-relationship --from --to --type indicates
# Import a STIX 2.1 bundle (upload + trigger import job)
python3 tools/clis/opencti.py upload-stix data/stix-bundles/2026-07-01-apt28-c2.json
# Delete an entity — DESTRUCTIVE. Confirm with the user first.
python3 tools/clis/opencti.py delete
All commands accept --dry-run (preview the GraphQL request without sending) and --insecure (skip TLS verification, common on internal deployments).
The CLI exits 2 if OPENCTI_URL or OPENCTI_TOKEN is unset (when not in dry-run). Report missing credentials; do not fabricate.
Indicators vs. observables
OpenCTI separates the two, and it matters for both reads and writes:
- Observable — a fact: "this IP exists in our data." No detection semantics, no validity window.
- Indicator — an assertion: "this pattern is malicious," with a STIX pattern, score, and valid-from/until window.
lookup checks both and reports which matched (known_as). When writing: use create-indicator for anything you'd want detections or blocklists built from, and let it create the companion observable (the default — don't pass --no-observable unless you have a reason; without the observable, raw value-searches won't find the IOC). Use create-observable for context-only sightings. Deleting an indicator does not cascade to its observable, and vice versa.
STIX 2.1 round-tripping
OpenCTI is STIX-native, so bundles from /stix-bundle import without the marking-definition surgery MISP needs:
- Run an investigation (e.g.
/ip-investigation) - Build a STIX bundle from the findings (
/stix-bundle) - Apply TLP + Admiralty (
/apply-tlp,/score-source) python3 tools/clis/opencti.py upload-stix- Review in OpenCTI → add context → connect to actors/campaigns
Import semantics: by default the CLI triggers the import with bypassValidation, which imports the bundle directly. With --no-bypass (or if your token lacks the bypass capability) the bundle lands in the analyst workbench (Data → Import) awaiting human validation — uploaded but not yet in the knowledge base. The CLI's response note tells you which happened; relay it. Import is asynchronous — poll with lookup/search; small bundles take seconds.
Response format
All commands return JSON:
source: opencti
operation: lookup | search | list | get | create-indicator | upload-stix | ...
query_time:
# lookup:
known: true|false
known_as: [observable, indicator]
observables: [...]
indicators: [...]
# list:
total_matches:
has_next_page: true|false
end_cursor:
results: [...]
# get:
entity: {...}
relationships: [...]
Source reliability (Admiralty default)
Default rating for downstream /score-source: B2 (usually reliable, probably true). OpenCTI is an aggregation platform — the rating belongs to the feed or author behind the entity, not the platform. Check createdBy and the entity's labels/markings:
- Your own analysts' entities (self-hosted instance) → A1 — primary source
- Reputable vendor connector (Mandiant, CrowdStrike, Recorded Future) → A2 / B2
- Open feeds (AlienVault, abuse.ch, MISP feed connectors) → B3 / C3
confidencefield on the entity (0-100) maps directly onto/confidence-levelsbands
Operational notes
- GraphQL errors arrive as HTTP 200 with an
errorsarray — the CLI surfaces the first message and exits 1.AUTH_REQUIREDmeans a bad or missing token. - Scores drive automation.
x_opencti_scorefeeds downstream decay and detection-export rules on many deployments. Don't inflate scores on write; 50 is neutral. - Labels are shared vocabulary.
add-labeland--labelsauto-create missing labels — checklist indicators --labelfor the existing convention before inventing a new one. - Deletes are silent and permanent. No recycle bin. Confirm with the user, and remember the indicator/observable non-cascade.
- pycti exists — for complex workflows (bulk imports with author identities, custom connectors, streaming) the official pycti library is the right tool. This CLI covers the 80% case for query + write, stdlib-only.
Related skills
/stix-bundle— write STIX 2.1 bundles that this CLI'supload-stixconsumes (OpenCTI accepts them as-is; no MISP-style TLP workaround needed)/lookup-misp— the sharing-platform sibling; OpenCTI = internal knowledge graph, MISP = community exchange/lookup-virustotal,/lookup-otx— community reputation lookups; chain before pushing into OpenCTI/score-source— apply Admiralty rating before publishing/apply-tlp— decide TLP beforeadd-marking/ip-investigation,/domain-investigation,/hash-investigation,/url-investigation— produce findings that OpenCTI write commands consume/threat-actor-profiling,/campaign-tracking— consumesearch/list/getoutput for actor and campaign context
See also
- Integration setup:
tools/integrations/opencti.md - Python CLI source:
tools/clis/opencti.py - OpenCTI project: https://filigran.io/solutions/open-cti/
- Documentation: https://docs.opencti.io/
- pycti (full SDK, when this CLI isn't enough): https://github.com/OpenCTI-Platform/client-python
- GraphQL playground:
$OPENCTI_URL/public/graphql(when enabled by the admin)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Liberty91LTD
- Source: Liberty91LTD/cti-skills
- License: MIT
- Homepage: https://liberty91.com/cti-skills
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.