Submit a sample under a GNAT investigation
Tag a submission with a GNAT investigation so every STIX object the analysis produces can be routed into that investigation’s evidence graph when GNAT pulls the bundle. The tag travels the whole pipeline — intake → detonation → STIX export — with zero heuristic matching on the GNAT side.
Reference: investigation-context.
When to do this
When the analyst already knows the investigation the sample belongs to at submission time. For retroactive linking after a correlator finds a connection, use the tagging endpoint instead.
Submitting
POST /submit accepts three optional form fields:
| Field | Required | Notes |
|---|---|---|
investigation_id |
optional | GNAT investigation primary key |
investigation_tenant_id |
optional | Multi-tenant correlation tag |
investigation_link_type |
optional | confirmed (default), inferred, suggested |
Both IDs must match ^[A-Za-z0-9_.:\-]+$ and are capped at 128 chars.
If investigation_id is absent, the other two are ignored (SandGNAT
has no standalone use for a tenant tag without an investigation).
curl -sS -H "X-API-Key: $INTAKE_API_KEY" \
-F "file=@/path/to/suspicious.exe" \
-F "investigation_id=IC-2026-0042" \
-F "investigation_tenant_id=acme-co" \
http://localhost:8080/submit
The response echoes the three fields back so a caller can confirm the tag stuck before Celery picks up the job:
{
"decision": "queued",
"analysis_id": "e3f1b4a2-...",
"sha256": "...",
"investigation_id": "IC-2026-0042",
"investigation_link_type": "confirmed",
"investigation_tenant_id": "acme-co"
}
What ends up in the STIX bundle
When the detonation completes, GET /analyses/<uuid>/bundle returns a
bundle whose objects[] starts with a STIX Grouping:
{
"type": "grouping",
"id": "grouping--...",
"context": "malware-analysis",
"name": "SandGNAT analysis e3f1b4a2-...",
"object_refs": ["malware--...", "file--...", "process--...", ...],
"x_gnat_investigation_id": "IC-2026-0042",
"x_gnat_investigation_origin": "sandgnat",
"x_gnat_investigation_link_type": "confirmed"
}
Every object referenced by object_refs also carries the three
x_gnat_investigation_* properties, so a consumer that reads one
object in isolation still gets the full context block.
Retroactive tagging (Phase 5)
If a link surfaces after the analysis has already completed (e.g. a correlator hit weeks later), an authorised client can tag the job without re-running the analysis:
curl -sS -X POST -H "X-API-Key: $INTAKE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"investigation_id":"IC-2026-0100","link_type":"inferred","tenant_id":"acme-co"}' \
http://localhost:8080/analyses/e3f1b4a2-.../investigation
link_type defaults to inferred on this endpoint — the retroactive
linkage is by definition not operator-asserted. The persisted STIX
bundle is not regenerated; the row-level tag is what changes. If
an analyst needs stamped objects reflecting the retroactive link,
GNAT re-stamps on its side with link_type="inferred" when it pulls
the bundle.
Re-tagging an already-tagged job returns 409 Conflict. Pass
?force=true to overwrite.
Filtering the export API by investigation
# Everything tagged to a specific investigation:
curl -sS -H "X-API-Key: $INTAKE_API_KEY" \
"http://localhost:8080/analyses?investigation_id=IC-2026-0042"
# Every tagged analysis (any investigation):
curl -sS -H "X-API-Key: $INTAKE_API_KEY" \
"http://localhost:8080/analyses?has_investigation=true"
# Every untagged analysis:
curl -sS -H "X-API-Key: $INTAKE_API_KEY" \
"http://localhost:8080/analyses?has_investigation=false"
Untagged analyses are unaffected
A submission without investigation_id produces the exact same
bundle bytes as before the investigation-context work shipped — no
stamping, no Grouping. The feature is strictly additive.