Campaign Ingestion System¶
Malwar supports automated ingestion of threat intelligence from external sources. You can import campaigns, IOCs (indicators of compromise), and detection signatures from JSON, CSV, and STIX 2.1 formats.
Supported Formats¶
| Format | CLI command | API source_type |
Description |
|---|---|---|---|
| JSON | malwar ingest json |
json |
Structured JSON matching Malwar's import schema |
| CSV | malwar ingest csv |
csv |
Simple tabular format with one IOC per row |
| STIX | malwar ingest stix |
stix |
STIX 2.1 JSON bundle (reverse of Malwar's export) |
| HTTP | malwar ingest url |
N/A | Fetch JSON or CSV from a remote URL |
JSON Schema Reference¶
The JSON import format uses the following structure:
{
"campaigns": [
{
"name": "CampaignName",
"attributed_to": "Threat Actor Name",
"first_seen": "2026-01-01",
"iocs": [
{"type": "domain", "value": "evil.com", "description": "C2 domain"},
{"type": "ip", "value": "1.2.3.4", "description": "C2 server"},
{"type": "url", "value": "http://evil.com/payload", "description": "Payload URL"},
{"type": "hash", "value": "abc123...", "description": "Malware SHA-256"}
],
"signatures": [
{
"pattern_type": "exact",
"pattern_value": "evil.com",
"ioc_type": "domain",
"severity": "critical",
"confidence": 0.95
}
]
}
]
}
Field Reference¶
Campaign fields:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Campaign identifier name |
attributed_to |
string | No | Threat actor attribution |
first_seen |
string | No | First seen date (YYYY-MM-DD) |
iocs |
array | No | List of IOC objects |
signatures |
array | No | List of signature objects |
IOC fields:
| Field | Type | Required | Values |
|---|---|---|---|
type |
string | Yes | ip, domain, url, hash |
value |
string | Yes | The indicator value |
description |
string | No | Human-readable description |
Signature fields:
| Field | Type | Required | Values |
|---|---|---|---|
pattern_type |
string | Yes | exact, regex, fuzzy, ioc |
pattern_value |
string | Yes | The pattern to match |
ioc_type |
string | Yes | ip, domain, url, hash |
severity |
string | No | critical, high, medium, low, info (default: medium) |
confidence |
float | No | 0.0 to 1.0 (default: 0.8) |
CSV Format Reference¶
The CSV format expects four columns with a header row:
campaign,ioc_type,ioc_value,severity
APT-Example,domain,evil.com,critical
APT-Example,ip,1.2.3.4,high
OtherCampaign,url,http://bad.example.com,medium
Column definitions:
| Column | Required | Description |
|---|---|---|
campaign |
Yes | Campaign name (rows with the same name are grouped) |
ioc_type |
Yes | IOC type: ip, domain, url, hash |
ioc_value |
Yes | The indicator value |
severity |
Yes | critical, high, medium, low, info |
Each row produces both an IOC and an exact-match detection signature.
STIX 2.1 Bundle Format¶
Malwar can ingest STIX 2.1 JSON bundles, including those exported by Malwar itself. The importer extracts:
- Campaign objects with
first_seenandlast_seendates - Threat-actor objects linked via
attributed-torelationships - Indicator objects with STIX patterns (mapped back to IOC types)
- Relationship objects (
indicates,attributed-to)
Supported STIX patterns:
- [ipv4-addr:value = '...'] maps to IOC type ip
- [domain-name:value = '...'] maps to IOC type domain
- [url:value = '...'] maps to IOC type url
- [file:hashes.'SHA-256' = '...'] maps to IOC type hash
CLI Usage Examples¶
Import from JSON file¶
Import from CSV file¶
Import from STIX bundle¶
Fetch and import from HTTP URL¶
# JSON feed (default)
malwar ingest url https://feeds.example.com/threats.json
# CSV feed
malwar ingest url https://feeds.example.com/indicators.csv --format csv
Example output¶
API Endpoint Reference¶
POST /api/v1/ingest¶
Import threat intelligence data via the REST API.
Authentication: Requires X-API-Key header (when API keys are configured).
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
source_type |
string | Yes | Format: json, csv, or stix |
data |
string | Yes | The content to import (stringified) |
Response (200 OK):
{
"campaigns_added": 1,
"campaigns_updated": 0,
"signatures_added": 3,
"signatures_skipped": 0,
"errors": []
}
Error responses:
| Status | Description |
|---|---|
| 401 | Missing API key |
| 403 | Invalid API key |
| 422 | Invalid payload or import failed |
Example using curl:
curl -X POST http://localhost:8000/api/v1/ingest \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"source_type": "json",
"data": "{\"campaigns\":[{\"name\":\"TestCampaign\",\"iocs\":[{\"type\":\"domain\",\"value\":\"evil.com\"}],\"signatures\":[{\"pattern_type\":\"exact\",\"pattern_value\":\"evil.com\",\"ioc_type\":\"domain\",\"severity\":\"critical\"}]}]}"
}'
Deduplication Behavior¶
The importer uses the following deduplication strategy:
-
Campaign matching: Campaigns are matched by
name. If a campaign with the same name already exists, it is considered a duplicate. -
Signature matching: Signatures are matched by the combination of campaign name and
pattern_value. If a signature with the same pattern value already exists for the same campaign, it is skipped. -
Merge mode (default): When importing into an existing campaign, new IOCs are merged into the campaign's IOC list. Existing IOCs (matched by value) are not duplicated.
-
Skip mode: If merge is disabled, existing campaigns are left unchanged but new signatures are still imported if they don't already exist.
Import result counts¶
| Field | Description |
|---|---|
campaigns_added |
Number of new campaigns created |
campaigns_updated |
Number of existing campaigns updated with new IOCs |
signatures_added |
Number of new signatures created |
signatures_skipped |
Number of signatures that already existed |
errors |
List of error messages (if any) |