Known-Bad IOC Feed (STIX)
Every malicious package the VDB detects contributes its C2/exfil infrastructure — domains, IPs, URLs — back into a public threat feed. The detection engine then matches future packages against that feed, so infrastructure burned in one attack flags the next package that reuses it.
This closes a loop between two halves of the system:
registry scanners ──▶ MalwareIoc / MalwareHost ──▶ malscan-stix-processor
▲ │
│ ▼
detect.Detect ◀── iocscan Matcher ◀── vulnetix.com/malscan-stix (STIX 2.1)
Publishing — malscan-stix-processor
cmd/malscan-stix-processor runs every 15 minutes. It reads the malware-IOC pipeline and writes per-ecosystem STIX 2.1 bundles to S3 (vdb-manager-artifacts), served unauthenticated at https://vulnetix.com/malscan-stix/…. Two feed kinds are published per ecosystem:
| Kind | Indicators | Source tables |
|---|---|---|
dns | Malicious domain-name + ipv4-addr / ipv6-addr | MalwareHost |
urls | Malicious C2 / exfil url | MalwareIoc + OsmThreatIoc |
Each indicator is a STIX indicator object with a pattern such as [domain-name:value = '…'], plus name, description, labels (carrying severity:* and ecosystem:*), external_references (the originating advisory) and valid_from.
Composite ecosystems (e.g. npm,pypi) fan out per ecosystem; anything outside a recognised package ecosystem lands in generic. Every feed is accompanied by a sibling <feed>.sha256, and a top-level index.json manifest lists every published feed with its URL, sha256 and indicator count. Feeds are deterministic — a file’s bytes change only when its indicator set changes.
Consuming — iocscan in the engine
The engine’s iocscan package consumes those feeds. A FeedLoader fetches index.json and the requested ecosystem’s dns + urls bundles (plus the always-included generic feed), caching each to the OS temp directory:
- The cache filename encodes a timestamp; freshness is read from it via a glob with a configurable 1-hour TTL.
- Fetched bytes are sha256-verified against the manifest before use.
- If a refetch fails (offline) or its checksum mismatches, the newest cached copy is used and a warning is returned in the result (the engine owns no logger). With no cache at all, the load errors.
The parsed indicators become an in-memory IndicatorSet with O(1) domain/IP/URL lookups. A Matcher then scans content — line-by-line over source text (with surrounding context lines), and optionally string-extracted from ELF/binary files — emitting evidence for any file that references a known-bad indicator, with full provenance: file path, line/byte offset, the matched line, and the STIX indicator’s name, severity and external references.
Wiring — every registry scanner
Each of the 16 registry processors loads the IndicatorSet once per run (via the internal/malscan helper, gated by the ioc-scan capability) and reuses one Matcher for every package — so per-package matching is an in-memory set lookup with no extra network or disk I/O. A match:
- Mints — it is folded into the finding set as
evidence(CWE-506) before the combination gate runs, so a package phoning a known C2 is flagged exactly like an inline payload. - Records — the matched value is persisted as a
MalwareIocrow whosereferencescarry the file/line and the STIX provenance — which the publisher then re-exports on its next run.
The same Matcher / Options.Set API is available to other callers (the CLI, ad-hoc scans); see the engine’s iocscan package. IOCs embedded in shipped binaries are supported by the engine (MatchBytes / Scan with BinaryAnalysis) but are only reached when a processor extracts package files to disk.