Articles on: Features & Tools

Malanta IOPA STIX/TAXII Feed - Integration Guide

Malanta IOPA STIX/TAXII Feed


TAXII 2.1 · STIX 2.1 · Pre-Attack Indicators · Clusters · Relationships


Version 1.0 | October 2026



Contents




Overview


Malanta delivers pre-attack threat intelligence over TAXII 2.1 as STIX 2.1 objects. Use this guide to connect your TIP, SOAR, SIEM, or custom collector.


The feed exposes Malanta’s attack-infrastructure graph so you can:


  • Ingest malicious / pre-attack indicators (primarily domains)
  • See clusters of related attack infrastructure (intrusion-set)
  • Follow relationships between indicators and clusters


Data is marked TLP:AMBER. Treat accordingly.


Support: support@malanta.ai


Base URL


Field

Value

Discovery URL

https://app.malanta.ai/feeds/taxii2

API root

https://app.malanta.ai/feeds/taxii2/default

Protocol

TAXII 2.1

Content

STIX 2.1


Always start from the discovery URL. Discovery advertises the API root; do not hardcode alternate hosts unless Malanta tells you to.


Collection


Collection ID

Title

Purpose

pre-attack-indicators

Malanta Pre-Attack Indicators

Indicators, clusters, and indicator↔cluster relationships


The collection is read-only (can_read: true, can_write: false).


↑ Back to top



Authentication


All requests require your Malanta API key. Keys are prefixed with malanta_. A missing or invalid key is rejected before the request reaches the service (401/403).


Supported transports (first match wins):


Priority

Method

Example

1

x-api-key header

x-api-key: malanta_xxxxxxxxxxxxx

2

Bearer

Authorization: Bearer malanta_xxxxxxxxxxxxx

3

HTTP Basic

Username: any string · Password: your API key


Recommended: x-api-key.


Basic Auth is provided for platforms (for example ThreatQ) that only expose username/password fields. Put the API key in the password field; username can be anything non-empty.


Required headers


Accept: application/taxii+json;version=2.1
x-api-key: malanta_xxxxxxxxxxxxx


Responses use Content-Type: application/taxii+json;version=2.1 and include X-TAXII-Content-Type with the same media type.


Keep your API key private. Never expose it in frontend code, mobile apps, or public repositories.


↑ Back to top



Endpoints


Base: https://app.malanta.ai/feeds/taxii2


Trailing slashes are accepted. Prefer not relying on HTTP redirects; redirects can drop auth headers.


Discovery


Endpoint: GET /taxii2


Returns TAXII server information and available API roots.


Example request


curl --request GET \
  --url 'https://app.malanta.ai/feeds/taxii2' \
  --header 'Accept: application/taxii+json;version=2.1' \
  --header 'x-api-key: malanta_xxxxxxxxxxxxx'


API root


Endpoint: GET /taxii2/default


Returns API root metadata (supported versions, max content length).


List collections


Endpoint: GET /taxii2/default/collections


Returns available collections.


Example request


curl --request GET \
  --url 'https://app.malanta.ai/feeds/taxii2/default/collections' \
  --header 'Accept: application/taxii+json;version=2.1' \
  --header 'x-api-key: malanta_xxxxxxxxxxxxx'


Collection metadata


Endpoint: GET /taxii2/default/collections/{collection_id}


Path parameters


  • collection_id — use pre-attack-indicators


Example request


curl --request GET \
  --url 'https://app.malanta.ai/feeds/taxii2/default/collections/pre-attack-indicators' \
  --header 'Accept: application/taxii+json;version=2.1' \
  --header 'x-api-key: malanta_xxxxxxxxxxxxx'


Get objects


Endpoint: GET /taxii2/default/collections/{collection_id}/objects


Returns STIX 2.1 objects in a TAXII envelope (paginated).


Path parameters


  • collection_id — use pre-attack-indicators


Query parameters


Param

Type

Default

Meaning

limit

integer

2000

Page size. Max response object count is 2002 (page + Malanta identity + TLP:AMBER marking).

next

string

none

Opaque pagination token from the previous response

added_after

RFC 3339

none

Only objects added after this time (incremental sync)


Example request


curl --request GET \
  --url 'https://app.malanta.ai/feeds/taxii2/default/collections/pre-attack-indicators/objects?limit=2000' \
  --header 'Accept: application/taxii+json;version=2.1' \
  --header 'x-api-key: malanta_xxxxxxxxxxxxx'


Example response


{
  "objects": [ /* STIX 2.1 SDOs / SROs */ ],
  "more": true,
  "next": "<opaque-token>"
}


Response fields


  • objects — STIX objects for this page
  • more — true → call again with next; false → drain complete
  • next — pagination token (present when more is true)


Response headers


Header

Meaning

X-TAXII-Date-Added-First

Earliest date_added / created on this page

X-TAXII-Date-Added-Last

Latest date_added / created on this page


Use X-TAXII-Date-Added-Last as the next added_after value for incremental sync.


Paginated request


curl --request GET \
  --url 'https://app.malanta.ai/feeds/taxii2/default/collections/pre-attack-indicators/objects?next=<token>' \
  --header 'Accept: application/taxii+json;version=2.1' \
  --header 'x-api-key: malanta_xxxxxxxxxxxxx'


Manifest


Endpoint: GET /taxii2/default/collections/{collection_id}/manifest


Returns object metadata without full STIX bodies. Same query parameters as Get objects (limit, next, added_after).


↑ Back to top



Pagination and incremental sync


Full drain (initial load)


1. GET .../objects?limit=2000
2. While response.more == true:
GET .../objects?next=<token>
3. When more == false → collection fully drained for this cycle


Do not keep polling the final token. When more is false, the cycle is finished.


Incremental sync (deltas)


Start a new request with added_after set to the last watermark you observed (typically X-TAXII-Date-Added-Last from the previous successful sync):


curl --request GET \
  --url 'https://app.malanta.ai/feeds/taxii2/default/collections/pre-attack-indicators/objects?limit=2000&added_after=2026-04-01T12:00:00.000Z' \
  --header 'Accept: application/taxii+json;version=2.1' \
  --header 'x-api-key: malanta_xxxxxxxxxxxxx'


Then follow next until more is false, same as a full drain.


added_after must be valid RFC 3339. Invalid values return HTTP 400 with a TAXII error resource.


Object order


Within one drain cycle, objects arrive in this order across pages:


  1. Indicators (reputation / observables)
  2. Clusters (intrusion-set)
  3. Relationships (indicator → cluster, type indicates)


A page never mixes streams; handoff to the next stream happens on the next HTTP call via next.


↑ Back to top




Pick one of these patterns for first-time onboarding, then stay on incremental API pulls. Do not invent a hybrid that starts mid-history with a date filter.


Important — clustering completeness. Your first load of the graph must be a complete baseline: either a Malanta full dump, or a TAXII drain with no added_after (empty date).


If the first TAXII call uses a specific added_after (for example “last 7 days”), you can lose clustering data. Older intrusion-set / relationship objects fall outside the window, while newer indicators may still appear — your TIP ends up with orphan indicators and a broken cluster graph. Only use added_after after a successful full baseline.


Use case A — Full dump, then API intervals


Best when: you need historical / inactive indicators as well as the live active set, and the full cluster graph in one shot.


Step

What

Notes

1

Request a full feed dump from Malanta

Includes active and inactive indicators, clusters, and relationships (baseline graph)

2

Load the dump into your TIP / store

Treat this as the complete starting state

3

Record a watermark

Use dump generation time, or run one TAXII drain and store X-TAXII-Date-Added-Last

4

Switch to TAXII incremental sync

GET .../objects?added_after=<watermark> on a schedule (e.g. daily)

5

Follow next until more=false each cycle

Same pagination rules as above


[Full dump: active + inactive + clusters + relationships]
↓
load once into TIP
↓
[TAXII] ?added_after=<watermark> → daily / hourly intervals


Contact your Malanta account team or support@malanta.ai to obtain the dump and confirm the handoff watermark.


Use case B — API full active set, then daily intervals


Best when: you only need the currently active feed via TAXII and do not require inactive history from a dump.


Step

What

Notes

1

TAXII full drain without added_after

GET .../objects?limit=2000 then follow next until more=false

2

Ingest all returned objects

Active indicators + clusters + relationships (complete active graph)

3

Persist watermark

Save X-TAXII-Date-Added-Last from the drain

4

Daily (or hourly) incremental

New cycle: GET .../objects?added_after=<watermark>


[TAXII] no added_after  →  full active baseline (indicators + clusters + relationships)
↓
persist X-TAXII-Date-Added-Last
↓
[TAXII] ?added_after=<watermark> → every day (or chosen interval)


What not to do


Anti-pattern

Why it fails

First sync with added_after=<some past date> and no prior dump/full drain

Misses older clusters/relationships → incomplete clustering

Skipping relationships / clusters and ingesting only indicators

Loses Malanta’s attack-infrastructure graph

Keeping the final next token forever instead of starting a new cycle with added_after

Incorrect vs TAXII finite-drain model; use a fresh request each interval


↑ Back to top



STIX object model


Every page begins with a short preamble:


  1. Malanta identity
  2. TLP:AMBER marking-definition


Then the page’s feed objects.


Indicator


Field

Notes

type

indicator

id

indicator--<uuid> — deterministic from Malanta observable id (stable across syncs)

name

Observable value (e.g. the domain or IP string)

pattern

STIX pattern, e.g. [domain-name:value = 'evil.example']

pattern_type

stix

indicator_types

Always malicious-activity

confidence

0–100 from Malanta malicious_score when present; otherwise 100

labels

Classification and provenance tags — see Labels

created

First observed time (first_observed_at)

modified

Last classified / updated time (last_classified_at)

valid_from

Same as created (validity starts when first observed)

valid_until

Not set on this TAXII feed today (no expiry emitted)

object_marking_refs

Points at TLP:AMBER

created_by_ref

Malanta identity


Supported observable types in patterns: domain-name, ipv4-addr, url, file (SHA-256).


Labels


Every indicator carries STIX labels so you can filter and prioritize in your TIP. Labels come from two places: always added by the feed, and passed through from Malanta’s reputation data when present.


Classification (always one of these)


Label

Meaning

IOPA

Indicator of Pre-Attack — Malanta’s core signal. Infrastructure observed during adversary setup (resource development), often weeks before it appears in classic IoC feeds. Always paired with source:malanta.

IOC

Indicator of Compromise — known malicious infrastructure already reported by the broader threat-intel ecosystem. Malanta redistributes and correlates it into the same cluster graph.


Always added by the feed


Label

Meaning

attack-infrastructure

Marker that the object is attack infrastructure (not a post-compromise host artifact alone).

Observable type

Raw type from the feed, e.g. domain, ip, url, hash — aligns with the STIX pattern type.

source:malanta

Always on IOPA. On IOC, only if a provider name is malanta (unusual).

source:<name>

On IOC — one label per external provider (e.g. source:proofpoint, source:github.com). Values are lowercased. Comma-joined providers are split into separate labels.

redistributed-by:malanta

On IOC when at least one provider is not Malanta — Malanta is redistributing an external indicator.


APT attribution (apt:…) — when available


Label

Meaning

apt:<name>

Linked APT / threat-actor name when Malanta has attribution for that indicator (e.g. apt:APT17, apt:APT5).


  • APT is returned only via labels — there is no separate STIX APT field on indicators or clusters in this feed.
  • Not every indicator has APT tags. If none are known, apt:… is simply omitted.
  • Comma-joined values are split so TIP filters can match exactly: apt:APT17,APT5 → apt:APT17 + apt:APT5.
  • Use apt:… for hunting, TIP tagging, and (with OpenCTI) connectors that map these labels to Intrusion Sets / Threat Actors.


Other pass-through labels (when available)


Upstream reputation labels are forwarded after normalization. Besides IOC / IOPA / apt:…, you may also see free-form or prefixed tags such as:


Label (examples)

Meaning

phishing

Category / technique tag from Malanta classification (example; not always present).

tag:<value> or other prefix:value

Additional taxonomy tokens when present upstream. Comma-joined prefix:a,b forms are expanded to one label per value.


Treat unknown labels as opaque tags — keep them for filtering; do not drop the indicator because a label is unfamiliar.


Cluster labels (on intrusion-set)


Clusters use a fixed label set (not the indicator taxonomy above):


Label

Meaning

attack infrastructure

Cluster represents related attack infrastructure.

source:malanta

Cluster is authored by Malanta.


How to use this as a customer


  • Prefer IOPA when you want Malanta’s early / predictive coverage (pre-attack).
  • Prefer IOC when you want confirmed malicious indicators with external provenance.
  • Many SOCs ingest both: IOPA for proactive blocking / hunting, IOC for correlation with existing TI feeds.
  • Use source:… to attribute origin; use apt:… when present for actor-focused triage.
  • Do not drop either class solely because the word “IOC” or “IOPA” is unfamiliar — both are first-class objects in this feed.


Cluster (intrusion-set)


A Malanta cluster is a group of related attack-infrastructure indicators that share ownership, certificates, or other linkage. In STIX it is published as an intrusion-set.


Field

Notes

type

intrusion-set

id

intrusion-set--<uuid> — deterministic from Malanta cluster_id (stable across syncs)

name

Short stable display name derived from the cluster id (not a human campaign title)

confidence

Always 100 for clusters in this feed

labels

Fixed set: attack infrastructure, source:malanta

created

When Malanta first built the cluster (first_built_at)

modified

When the cluster was last updated (last_updated_at)

object_marking_refs

Points at TLP:AMBER

created_by_ref

Malanta identity


How to use this as a customer


  • Treat each intrusion-set as a cluster of related infrastructure, not necessarily a named APT group.
  • Join indicators to clusters via relationships (below) — do not invent joins from indicator labels alone.
  • Keep clusters even if you primarily alert on indicators; without them the graph (and indicates edges) is incomplete.


Relationship


Edges that connect indicators to clusters. In this feed every relationship is type indicates: the indicator points at the intrusion-set it belongs to.


Field

Notes

type

relationship

id

relationship--<uuid> — deterministic from indicator id + cluster id (stable across syncs)

relationship_type

Always indicates

source_ref

STIX id of the indicator (indicator--…)

target_ref

STIX id of the cluster (intrusion-set--…)

created

When Malanta first recorded the membership (system_created_at)

modified

When the membership was last updated (system_updated_at)

object_marking_refs

Points at TLP:AMBER

created_by_ref

Malanta identity


Direction


indicator  --indicates-->  intrusion-set (cluster)


How to use this as a customer


  • Resolve source_ref / target_ref against objects already ingested (or pending in the same drain).
  • Because object order is indicators → clusters → relationships, a full drain without added_after (or a dump baseline) keeps refs resolvable.
  • STIX IDs for indicators, clusters, and relationships are deterministic (stable across days), so TIP snapshot diffs stay clean.


↑ Back to top



Platform setup examples


OpenCTI


  1. Data → Connectors (or Ingestion) → add a TAXII 2 connector / feed.
  2. Discovery URL: https://app.malanta.ai/feeds/taxii2
  3. Auth: API key via x-api-key or Bearer, depending on connector fields.
  4. Select collection pre-attack-indicators.
  5. Enable periodic sync. Prefer connectors that honor added_after / date-added headers for deltas.


OpenCTI expects a finite drain (more: false) then a new poll with a time filter — that matches Malanta’s behavior.


ThreatQ


  1. TAXII URL: https://app.malanta.ai/feeds/taxii2
  2. Username: your org name or any placeholder
  3. Password: your full malanta_… API key
  4. Collection: pre-attack-indicators


Python


import httpx

BASE = "https://app.malanta.ai/feeds"
HEADERS = {
"Accept": "application/taxii+json;version=2.1",
"x-api-key": "malanta_xxxxxxxxxxxxx",
}

def drain_collection(collection_id: str, *, added_after: str | None = None):
params: dict = {"limit": 2000}
if added_after:
params["added_after"] = added_after

url = f"{BASE}/taxii2/default/collections/{collection_id}/objects"
watermark = added_after

with httpx.Client(headers=HEADERS, timeout=120.0) as client:
while True:
r = client.get(url, params=params)
r.raise_for_status()
body = r.json()
yield from body.get("objects") or []

last = r.headers.get("X-TAXII-Date-Added-Last")
if last:
watermark = last

if not body.get("more"):
break
params = {"next": body["next"]} # do not re-send limit/added_after with next

return watermark


cURL smoke test


curl --request GET \
  --url 'https://app.malanta.ai/feeds/taxii2' \
  --header 'Accept: application/taxii+json;version=2.1' \
  --header 'x-api-key: malanta_xxxxxxxxxxxxx'


Expected: JSON with title, default, and api_roots.


curl --request GET \
  --url 'https://app.malanta.ai/feeds/taxii2/default/collections/pre-attack-indicators/objects?limit=10' \
  --header 'Accept: application/taxii+json;version=2.1' \
  --header 'x-api-key: malanta_xxxxxxxxxxxxx'


↑ Back to top



Errors


Status

When

What to do

400

Bad query (e.g. invalid added_after or next)

Fix parameter; do not reuse a corrupt token

401 / 403

Missing or invalid API key / plan

Check key; contact Malanta

404

Unknown API root or collection

Confirm path and collection ID

429

Rate limited

Back off and retry

5xx

Transient server error

Retry with backoff


TAXII error bodies follow TAXII 2.1 error resources, for example:


{
  "title": "Invalid Query Parameter",
  "description": "...",
  "http_status": "400"
}


↑ Back to top



Limitations


  • Collection object-by-id lookup resolves the Malanta identity and TLP:AMBER marking. Individual feed indicators / clusters / relationships are consumed via the paginated /objects stream.
  • match[…] query filters may be accepted by the router; rely on collection choice + added_after for supported filtering unless Malanta confirms additional match support for your account.
  • Feed is pull-only (no TAXII write / inbox).


↑ Back to top



Quick reference


  • Discovery: https://app.malanta.ai/feeds/taxii2
  • API root: https://app.malanta.ai/feeds/taxii2/default
  • Collection: pre-attack-indicators
  • Auth: x-api-key: malanta_xxxxxxxxxxxxx (also Bearer / Basic)
  • Accept: application/taxii+json;version=2.1
  • Baseline (once): full dump (active+inactive) or TAXII with no added_after (active only)
  • Then intervals: GET objects?added_after=<watermark> → while more: follow next → stop
  • Always baseline first before any dated incremental — otherwise clustering can break
  • Respect TLP:AMBER — do not redistribute outside your organization without agreement


Questions or onboarding help: support@malanta.ai


↑ Back to top

Updated on: 13/10/2026

Was this article helpful?

Share your feedback

Cancel

Thank you!