Malware Analysis Module

July 18, 2026 · View on GitHub

Introduced in v4.0 and available in the latest tagged v6.0.0 release, Malware Analysis is backed by the isolated MalwareGraph service. All static, unpacking, string, decompilation, and AI output is analyst-assistance data. Validate every finding before using it in incident response, detection deployment, customer reporting, or attribution.

For the full walkthrough article see docs/publication-drafts/adversarygraph-v4-malware-analysis.md.


Contents

  1. What the module does
  2. Architecture and deployment modes
  3. Technology stack
  4. Screenshots
  5. Safety model
  6. Configuration reference
  7. API endpoints reference
  8. Use cases

What the module does

The Malware Analysis module connects AdversaryGraph to an isolated MalwareGraph service for static malware analysis. It gives analysts a single workflow dashboard where every extracted hash, IP, domain, ATT&CK technique, string, function, and family lead is a clickable entity that links back into the AdversaryGraph graph (IOC Library, IOC Intelligence, ATT&CK Navigator, Compare Groups, Detection Studio).

Core capabilities available today:

CapabilityRoute / action
Sample submission (raw file or password-protected ZIP)POST /api/malwaregraph/analyses
Analysis status and first-analysis dataGET /api/malwaregraph/analyses/{job_id}
Structured report (IOCs, TTPs, hashes, behaviors)GET /api/malwaregraph/analyses/{job_id}/report
String extraction with length and reference filtersGET /api/malwaregraph/analyses/{job_id}/strings
Hex / ASCII / strings file previewGET /api/malwaregraph/analyses/{job_id}/files/preview
Static unpackPOST /api/malwaregraph/analyses/{job_id}/unpack
Dynamic/runtime unpack (policy-gated)POST /api/malwaregraph/analyses/{job_id}/unpack/runtime
Obfuscation technique analysisPOST /api/malwaregraph/analyses/{job_id}/obfuscation-analysis
AI full analysis pipelinePOST /api/malwaregraph/analyses/{job_id}/ai-full-analysis
Debug session (static analyst-guided plan)POST /api/malwaregraph/analyses/{job_id}/debug-sessions
Debug workspace (AI-assisted step-through)POST /api/malwaregraph/analyses/{job_id}/debug-workspaces
Decompilation metadataPOST /api/malwaregraph/analyses/{job_id}/decompilation
Analysis workflow graphGET /api/malwaregraph/analyses/{job_id}/workflow-graph
Analysis and service logsGET /api/malwaregraph/analyses/{job_id}/logs, GET /api/malwaregraph/logs
LLM provider enumerationGET /api/malwaregraph/llm/providers
Custom LLM prompt completionPOST /api/malwaregraph/llm/complete
Service healthGET /api/malwaregraph/health

Architecture and deployment modes

┌─────────────────────────────────────────────────────────────────────────────┐
│                            AdversaryGraph                                   │
│  React UI ──── FastAPI backend ──── PostgreSQL / Redis / Celery             │
│       │               │                                                     │
│  Malware Analysis      └──────── MalwareGraphClient ─────────┐              │
│  page (MalwareAnalysis.tsx)      (proxy client, port 8000)   │              │
└──────────────────────────────────────────────────────────────┼─────────────┘
                                                               │ REST API

                                    ┌─────────────────────────────────────┐
                                    │   MalwareGraph service (port 8100)  │
                                    │   FastAPI · static analysis workers │
                                    │   quarantine storage · job queue    │
                                    └─────────────────────────────────────┘

Integrated mode

The default. The AdversaryGraph frontend talks to the AdversaryGraph backend (/api/malwaregraph/*), which proxies every request to the MalwareGraph service through MalwareGraphClient. The MalwareGraph service is on the malwaregraph_internal Docker network, not exposed on the host.

Standalone mode

The MalwareGraph service is accessed directly at http://localhost:8100 from the host or from scripts. Use this when running analysis separately from AdversaryGraph or for scripted batch processing. The same analysis.json contract is produced in both modes.


Technology stack

This section lists the real libraries, binaries, and code modules used by the current implementation.

AreaActually usedWhat it does
MalwareGraph APIfastapi, uvicorn[standard], python-multipart, malwaregraph.api.appServes analysis, upload, strings, unpack, decompilation, debug, runtime, report, logs, and provider endpoints.
Models and settingspydantic, pydantic-settings, malwaregraph.core.models, malwaregraph.core.configDefines API contracts, job records, graph entities, debug/session models, and environment configuration.
Archive handlingPython zipfile, pyzipper, malwaregraph.services.archiveExtracts ZIP/password-protected ZIP samples into isolated MalwareGraph storage.
HashingPython hashlib, malwaregraph.services.hashingCalculates MD5, SHA1, and SHA256.
Static PE/file parserPython struct, math, pathlib, malwaregraph.services.static_analysisPerforms file classification, entropy, PE header parsing, sections, imports, resources, and first-analysis artifacts.
Packer detectionmalwaregraph.services.packing, malwaregraph.services.unpackUses UPX markers, section names, entropy, import scarcity, overlay and encoded-payload heuristics.
Static depackingupx-ucl binary, Python subprocess, zlib, bz2, lzma, base64, XOR scanner in malwaregraph.services.unpackRuns upx -d for UPX and tries bounded recovery of compressed, encoded, or XOR-like payloads.
Runtime depackingunipacker==1.0.8, child-process wrapper in malwaregraph.services.unpackHandles policy-gated PE32 runtime unpack attempts. Qiling is referenced only as a planned/profile name and is not installed.
Strings and decodingPython re, base64, JSON helpers, malwaregraph.services.stringsExtracts ASCII/UTF-16LE strings, decodes base64/hex candidates, scores entropy, and classifies string findings.
IOC extractionPython re, ipaddress, urllib.parse, malwaregraph.services.iocsExtracts URLs, domains, IPs, hashes, emails, registry paths, and related IOC values.
Android/APK static supportPython zipfile, malwaregraph.services.androidPerforms static APK/archive inspection and Android-related IOC/string extraction.
Disassemblycapstone>=5, malwaregraph.services.workflow_graph, malwaregraph.services.debug_workspaceDisassembles x86/x64 PE code and builds workflow/function traces. Falls back to hex preview if Capstone is unavailable.
Decompile viewmalwaregraph.services.decompilationBuilds MalwareGraph's internal static pseudocode artifact from PE metadata, WinAPI strings, entrypoint details, and sections. It is not Ghidra/IDA/RetDec output.
Debug workspacemalwaregraph.services.debug_workspace, in-memory workspace dictionaryProvides function stepping, breakpoints, register/stack snapshots, memory regions, API hooks, graph export, and AI debug context.
AI callshttpx, malwaregraph.services.ai.factoryCalls Claude, OpenAI, Gemini, MiniMax/OpenAI-compatible, local OpenAI-compatible endpoints, or AdversaryGraph's LLM proxy.
AdversaryGraph proxyhttpx, backend/app/services/malwaregraph.py, backend/app/api/routes/malwaregraph.pyProxies /api/malwaregraph/* from AdversaryGraph to MalwareGraph.
FrontendReact 18, Vite, TypeScript, Tailwind CSS, @tanstack/react-query, axios, react-router-domImplements the malware dashboard, strings view, unpacker, dynamic analysis, and debugger/decompiler UI.
Container runtimeDocker Compose, python:3.12-slim, node:22-slim, read-only service, dropped capabilities, no-new-privileges, PID/CPU/memory limitsRuns MalwareGraph in a restricted container and builds the bundled MalwareGraph UI.

Not currently bundled as malware-analysis engines: Ghidra, IDA Pro, RetDec, pefile, CAPE/Cuckoo, YARA, Volatility, Frida, or Qiling execution.


Screenshots

The v4 screenshot folder name is historical. These screenshots remain representative for the tagged v6.0.0 Malware Analysis workflow unless a newer module-specific screenshot is listed. They show the implemented workflow rather than mockups. The complete asset list is tracked in docs/assets/malware-analysis-v4/manifest.md, and validation.json records the dimension and nonblank checks for each 1920x1200 PNG.

Malware Analysis dashboard

Malware Analysis dashboard

Shows case controls, service status, safety record, first-analysis results, hash-check entry point, and section entropy visualization.

Hash-check feed results

Hash-check feed results

Shows the post-action feed result panel. The result window is wide enough for VirusTotal-style counts, reputation, family names, local IOC feed results, and external feed summaries without cutting the content.

First-analysis tools

First-analysis tools

Shows the first-analysis action area: static facts, section entropy, hash check, string analysis, unpacking, debug, report, and dynamic-analysis entry points.

Report, IOCs, and TTPs

Report, IOCs, and TTPs

Shows the report section where extracted IOCs, clickable ATT&CK TTP tags, suspicious functions, analyst notes, and validation gaps are kept with evidence.

String Analyzer - all strings

String Analyzer - all strings

Shows extracted ASCII/UTF-16 string review, target metrics, category counts, and filters for analyst-controlled triage.

String Analyzer - smart IOC/TTP leads

String Analyzer - smart IOC/TTP leads

Shows smart mode, where the module groups registry keys, commands, URLs, domains, hashes, suspicious API names, and ATT&CK-style leads for faster review.

String Analyzer - AI mode

String Analyzer - AI mode

Shows AI string-analysis mode and provider selection. The visible result depends on local LLM availability; the UI keeps the provider state separate from the raw string evidence.

Unpacker - packed sample

Unpacker - packed sample

Shows a packed Windows sample profile with packer name, entropy, obfuscation flags, file versions, static unpack controls, AI unpack action, and dynamic unpack gate.

Unpacker - deobfuscation actions

Unpacker - deobfuscation actions

Shows follow-on deobfuscation controls for strings and code after packer triage, plus navigation back to the case and onward to strings, debug, and dynamic analysis.

Debugger - decompilation IDE

Debugger - decompilation IDE

Shows the IDE-style decompilation pane, recovered static APIs, entrypoint details, controls, breakpoints, and dynamic-analysis safety gate.

Debugger - after step

Debugger - after step

Shows debugger state after one safe symbolic function step. This verifies that the UI can create a workspace, advance function-level analysis, and keep step results visible.

Debugger - OllyDbg CPU view

Debugger - OllyDbg CPU view

Shows the CPU-style debug panel with disassembly, registers, stack, memory/API context, and AI notes for the current function.

Debugger - function graph

Debugger - function graph

Shows the AIDebug function graph and selected function context used to move between recovered code blocks and AI-assisted explanations.

Dynamic Analysis - safety gate

Dynamic Analysis - safety gate

Shows runtime target selection, AI provider selection, and the explicit dynamic-analysis disclaimer before any isolated runtime session is prepared.

Dynamic Analysis - runtime session

Dynamic Analysis - runtime session

Shows the prepared isolated runtime session, runtime profile, control state, and behavior categories that are expected from dynamic output.

Dynamic Analysis - function workflow

Dynamic Analysis - function workflow

Shows the loaded full function workflow, function stepping controls, branch context, and AI feedback-loop entry points for summarizing dynamic behavior.


Safety model

The default execution policy is static-only. Submitted samples are never executed unless dynamic analysis is explicitly enabled.

ControlDefaultNotes
Sample executionDisabledRequires dynamic_analysis: true in the request AND MALWAREGRAPH_ENABLE_DYNAMIC_DEBUG=true in service env
Outbound internet from analysis jobsDisabledWorkers have no external network route
Binary upload to third-party servicesDisabledOnly hash lookups by default
Host filesystem accessDeniedWorkers use dedicated quarantine and scratch volumes
runtime_debug_disclaimer_acceptedfalseMust be explicitly true for any runtime-debug action
Network between MalwareGraph and AdversaryGraph DBDeniedmalwaregraph_internal is isolated

Do not upload real malware samples to public or shared AdversaryGraph installations. Use a private self-hosted deployment.


Configuration reference

Set in .env at the AdversaryGraph project root:

MALWAREGRAPH_URL=http://malwaregraph:8100          # service URL (default for Docker Compose)
MALWAREGRAPH_API_KEY=                               # optional API key sent as X-API-Key
MALWAREGRAPH_REQUEST_TIMEOUT_SECONDS=30             # short-request timeout
MALWAREGRAPH_UPLOAD_TIMEOUT_SECONDS=180             # sample upload timeout
MALWAREGRAPH_LONG_TIMEOUT_SECONDS=300               # AI/RE/unpack operation timeout
MALWAREGRAPH_STORAGE_DIR=/malwaregraph-storage      # shared storage for saved layers

For standalone testing from the host machine, override the URL:

MALWAREGRAPH_URL=http://localhost:8100

API endpoints reference

All proxy routes live under /api/malwaregraph/.

Health and providers

MethodPathNotes
GET/api/malwaregraph/healthReturns service version and status dict
GET/api/malwaregraph/llm/providersReturns available LLM provider list
GET/api/malwaregraph/logsReturns service-level log lines (?limit=N)

Analysis lifecycle

MethodPathNotes
GET/api/malwaregraph/analysesList all jobs
POST/api/malwaregraph/analysesSubmit a sample (multipart: file, optional password, case_id, dynamic_analysis, runtime_debug_disclaimer_accepted)
GET/api/malwaregraph/analyses/{job_id}Get job status and first-analysis data
GET/api/malwaregraph/analyses/{job_id}/reportGet full structured report
GET/api/malwaregraph/analyses/{job_id}/logsGet per-job log lines (?limit=N)
GET/api/malwaregraph/analyses/{job_id}/workflow-graphGet workflow/debug graph (nodes and edges)

Static analysis tools

MethodPathNotes
GET/api/malwaregraph/analyses/{job_id}/stringsString extraction (sample_ref, min_chars, max_chars, ai, ai_provider)
GET/api/malwaregraph/analyses/{job_id}/files/previewFile preview (mode: strings, ascii, hex; limit; sample_ref)
POST/api/malwaregraph/analyses/{job_id}/unpackStatic unpack job (sample_ref, dynamic_analysis, runtime_debug_disclaimer_accepted)
POST/api/malwaregraph/analyses/{job_id}/unpack/runtimeRuntime/dynamic unpack (policy-gated)
POST/api/malwaregraph/analyses/{job_id}/obfuscation-analysisObfuscation technique analysis (sample_ref, ai_provider)
POST/api/malwaregraph/analyses/{job_id}/decompilationDecompilation metadata (sample_ref)
POST/api/malwaregraph/analyses/{job_id}/save-unpackedSave unpacked layers to MALWAREGRAPH_STORAGE_DIR

AI analysis

MethodPathNotes
POST/api/malwaregraph/analyses/{job_id}/ai-full-analysisFull pipeline AI analysis (sample_ref, ai_provider, dynamic_analysis, prefer_unpacked_output)
POST/api/malwaregraph/llm/completeDirect LLM prompt completion (provider: local|claude|openai|gemini|minimax, model, system, prompt)

Debug sessions and workspaces

MethodPathNotes
POST/api/malwaregraph/analyses/{job_id}/debug-sessionsCreate analyst-guided debug session
POST/api/malwaregraph/analyses/{job_id}/runtime-debug-sessionsCreate dynamic runtime debug session (policy-gated)
POST/api/malwaregraph/analyses/{job_id}/debug-workspacesCreate AI-assisted debug workspace (ai_provider)
GET/api/malwaregraph/debug-workspaces/{session_id}Get workspace state and steps
POST/api/malwaregraph/debug-workspaces/{session_id}/stepAdvance workspace by one step
POST/api/malwaregraph/debug-workspaces/{session_id}/ai-assistantRun AI assistant in workspace context
POST/api/malwaregraph/runtime-debug-sessions/{session_id}/stepAdvance runtime debug session

Use cases

The examples below describe analyst workflows. Do not commit or download live malware into this repository. For real Windows malware, use only authorized samples supplied by your organization, incident-response case, or a controlled private corpus, and store them outside the Git worktree in an isolated malware lab. Keep samples password-protected at rest and run dynamic workflows only in a disposable runtime profile.

Scenario set — Five Windows malware-analysis profiles

Use these profiles to validate the module from low risk to high complexity.

ProfileSample typeWhat it validatesRecommended handling
Clean controlKnown-good Windows PE such as a signed Microsoft utility or your own compiled benign PEBaseline file identity, PE parsing, entropy, imports, strings, false-positive control, report wordingSafe static analysis. Do not mark it malicious; use it to compare UI output and AI caution.
Simple packed sampleAuthorized Windows PE packed once with a common packer such as UPXPacker detection, high entropy, static unpack output, before/after hashes and entropy deltaStart with static unpack. Dynamic execution should not be needed if static unpack succeeds.
Packed malware requiring runtime unpackAuthorized Windows malware where static unpack fails and unpacking needs runtime state or memory dumpRuntime-unpack planning, policy gate, validation gaps, unpacked target selection, AI explanation of why runtime is requiredEnable dynamic only inside a disposable sandbox or VM profile with no production network route.
Obfuscated code malwareAuthorized Windows malware or script-backed PE with encoded strings, API hashing, encrypted config, or control-flow tricksObfuscation analysis, AI string classification, suspicious API/function explanation, validation-gap trackingKeep output as hypotheses until deobfuscation or runtime stepping confirms behavior.
Multilayer packed malwareAuthorized Windows malware with nested packers, loaders, droppers, or staged payload extractionLayer tracking, repeated unpack/inject-file workflow, per-layer target selection, IOC/TTP correlation across layersAnalyze one layer at a time. Save each unpacked/deobfuscated output as a new target and preserve evidence links.

Suggested sample-corpus layout outside the repo:

/malware-lab/samples/windows/
  clean-control/
  simple-packed/
  runtime-unpack-required/
  obfuscated-code/
  multilayer-packed/

For each sample, keep a companion note with:

  • source and authorization
  • original filename
  • SHA256
  • password, if zipped
  • expected profile
  • whether runtime execution is permitted
  • network policy: none, fakenet, sinkhole, or restricted lab internet

Never use public demo infrastructure for these profiles. The dynamic and runtime-unpack profiles require MALWAREGRAPH_ENABLE_DYNAMIC_DEBUG=true, dynamic_analysis=true, and explicit acceptance of the runtime-debug disclaimer.


Use case 1 — Submit a raw sample for first triage

When: An analyst receives a suspicious .exe, .dll, or script and wants an immediate static metadata overview.

Steps:

curl -X POST http://localhost:8000/api/malwaregraph/analyses \
  -F "file=@suspicious.exe" \
  -F "case_id=MAL-2026-001"

The response returns a job_id. Use it for all subsequent steps:

curl http://localhost:8000/api/malwaregraph/analyses/{job_id}

Review: file_type, hashes (MD5/SHA256/imphash/tlsh/ssdeep), entropy, packer_hints, sections, imports.

In the UI: Open Malware Analysis, set a case name and case ID, attach the file, and click Create case and run first analysis.


Use case 2 — Submit a password-protected malware ZIP

When: A vendor or threat intel team delivers samples inside an encrypted archive using the conventional password infected.

Steps:

curl -X POST http://localhost:8000/api/malwaregraph/analyses \
  -F "file=@samples.zip" \
  -F "password=infected" \
  -F "case_id=MAL-2026-002"

The intake service extracts the archive inside an isolated container with path traversal, file count, and decompression-bomb limits. Each extracted file becomes a separate analysis target accessible via the sample_ref parameter.

In the UI: The file picker shows a ZIP password field when a .zip file is selected. Default password is pre-filled as infected.


Use case 3 — Check what targets were extracted from an archive

When: The submitted archive contained multiple payloads and the analyst needs to identify which target to analyze.

curl http://localhost:8000/api/malwaregraph/analyses/{job_id}

Look at the first_analyses array — each entry has a target_entity_id (e.g., archive--file--0001, archive--file--0002) and the file type, name, size, and entropy of the extracted file.

Subsequent API calls use ?sample_ref=archive--file--0002 to target a specific extracted file. In the UI, the target selector dropdown lists all extracted targets.


Use case 4 — Extract strings from a sample

When: An analyst wants to identify hardcoded URLs, IP addresses, registry keys, commands, mutex names, or encoded configuration.

curl "http://localhost:8000/api/malwaregraph/analyses/{job_id}/strings?\
sample_ref=archive--file--0001&min_chars=4"

Useful filters:

ParameterPurpose
min_charsFilter out short noise strings (default: 4)
max_charsCap on string length for focused extraction
sample_refTarget a specific extracted file
ai=falseReturn raw strings without AI classification (faster)
ai=trueAdd AI classification into IOC categories, commands, WinAPI calls

The response strings array includes the raw string, its offset, and (when ai=true) an AI-assigned category.


Use case 5 — Run AI string classification

When: Raw string extraction returns thousands of entries and the analyst needs them categorized into IOC candidates, commands, WinAPI calls, registry keys, network indicators, and evasion strings.

curl "http://localhost:8000/api/malwaregraph/analyses/{job_id}/strings?\
sample_ref=archive--file--0001&ai=true&ai_provider=local"

AI string categories returned by MalwareGraph:

  • ioc_ip, ioc_domain, ioc_url, ioc_email
  • command, powershell, registry_key, file_path, mutex
  • winapi, android_api
  • credential, encryption_key
  • network_c2, persistence, defense_evasion, execution

Switch to a more capable model for complex obfuscated code:

... &ai=true&ai_provider=claude

Use case 6 — Preview file content in hex, ASCII, or strings mode

When: An analyst wants a quick look at the binary content to spot magic bytes, decode a configuration block, or verify a sample type by eye.

# Strings mode (default)
curl "http://localhost:8000/api/malwaregraph/analyses/{job_id}/files/preview?\
sample_ref=archive--file--0001&mode=strings&limit=200"

# Hex mode — useful for magic byte inspection and section analysis
curl "http://localhost:8000/api/malwaregraph/analyses/{job_id}/files/preview?\
mode=hex&limit=64"

# ASCII mode — plaintext decoders, base64 blobs, script payloads
curl "http://localhost:8000/api/malwaregraph/analyses/{job_id}/files/preview?\
mode=ascii&limit=200"

In the UI, the preview panel sits below the first-analysis metadata with a Strings / ASCII / Hex toggle.


Use case 7 — Unpack a packed executable

When: Static triage shows high entropy, a known packer (UPX, MPRESS, custom), or a stub-only import table — indicating the real payload is unpacked at runtime.

curl -X POST "http://localhost:8000/api/malwaregraph/analyses/{job_id}/unpack?\
sample_ref=archive--file--0001"

The unpack job attempts static decompression first. On success, the unpacked layer becomes a new sample_ref target (e.g., archive--file--0002). Re-run strings, preview, and AI analysis against the unpacked target.

To save the unpacked layers to disk for external tooling:

curl -X POST http://localhost:8000/api/malwaregraph/analyses/{job_id}/save-unpacked

Layers are written to MALWAREGRAPH_STORAGE_DIR/{job_id}/. Returns 404 if no layers exist yet.


Use case 8 — Run obfuscation technique analysis

When: A script (PowerShell, JScript, VBScript) or shellcode uses encoding, string splitting, variable substitution, API hashing, or layered encryption that the strings pass misses.

curl -X POST "http://localhost:8000/api/malwaregraph/analyses/{job_id}/obfuscation-analysis?\
sample_ref=archive--file--0001&ai_provider=local"

The response includes an obfuscation score (0–1), a list of identified techniques (e.g., xor_encode, base64, string_concat, api_hash), and AI-generated recommendations for next steps.

Use a more capable provider for complex multi-stage obfuscated loaders:

... &ai_provider=claude

Use case 9 — Run the full AI analysis pipeline

When: An analyst wants a comprehensive AI-assisted pass over a completed static analysis: IOC classification, ATT&CK TTP mapping, behavior summary, family hypotheses, and detection drafts — all in one operation.

curl -X POST "http://localhost:8000/api/malwaregraph/analyses/{job_id}/ai-full-analysis?\
sample_ref=archive--file--0001&ai_provider=claude&prefer_unpacked_output=true"

The prefer_unpacked_output=true flag tells the AI pipeline to use the deepest available unpacked layer instead of the original archive, which produces better TTP mapping when a packer was present.

Expected output sections:

  • ioc_analysis — normalized IOCs with type and confidence
  • ttp_candidates — ATT&CK technique IDs, tactic, evidence strings
  • behavior_summary — capability narrative
  • family_hypotheses — malware family leads with evidence
  • detection_draft — raw YARA/Sigma snippet ideas
  • analyst_notes — AI-identified uncertainty and recommended next steps

In the UI: Click Run full AI analysis in the AI Analysis panel.


Use case 10 — Retrieve the structured analysis report

When: The analyst has completed static triage and wants the canonical analysis.json-style report with all normalized findings.

curl http://localhost:8000/api/malwaregraph/analyses/{job_id}/report

The report includes:

  • sample — names, hashes (MD5/SHA1/SHA256/imphash/tlsh/ssdeep), file type, size
  • iocs — each with type, value, source stage, confidence
  • attack_mappings — technique ID, tactic, evidence, review state
  • behaviors — capability descriptions with supporting artifact refs
  • family_hypotheses — malware family leads with evidence categories
  • safety — records whether the sample was executed, the sandbox profile, and whether binary upload to third-party services occurred
  • ai_assistance — all AI output marked as untrusted analyst assistance

Use case 11 — Get the workflow/debug graph

When: An analyst wants to understand the analysis stages, their dependencies, and any debug-plan nodes in a visual graph layout.

curl http://localhost:8000/api/malwaregraph/analyses/{job_id}/workflow-graph

The response contains a nodes array (each with type, stage, label, and status) and an edges array. Render this in a graph viewer or import it into the AdversaryGraph Investigation Graph. For static-only jobs, the graph shows triage, strings, unpack, deobfuscation, and AI-synthesis nodes. Debug nodes populate only when a debug session or dynamic evidence exists.


Use case 12 — Create an analyst-guided debug session

When: The analyst wants to map the reversing plan — which functions to examine, what breakpoints to set, what memory addresses to dump — without needing a live runtime environment.

curl -X POST "http://localhost:8000/api/malwaregraph/analyses/{job_id}/debug-sessions?\
sample_ref=archive--file--0001"

The response returns a session_id. Each session stores a planned debug sequence. On a deployment with runtime debug enabled, the same session can drive live execution. Use the session for tracking analyst notes and building the reversing evidence trail before escalating to dynamic analysis.


Use case 13 — Use an AI-assisted debug workspace

When: An analyst wants step-by-step AI guidance through a reversing or triage sequence — the AI proposes what to examine next, explains what it sees, and updates its plan as the analyst advances.

# Create the workspace
curl -X POST "http://localhost:8000/api/malwaregraph/analyses/{job_id}/debug-workspaces?\
sample_ref=archive--file--0001&ai_provider=local"

# Retrieve workspace state
curl http://localhost:8000/api/malwaregraph/debug-workspaces/{session_id}

# Advance by one step
curl -X POST http://localhost:8000/api/malwaregraph/debug-workspaces/{session_id}/step

# Ask the AI assistant a question in workspace context
curl -X POST "http://localhost:8000/api/malwaregraph/debug-workspaces/{session_id}/ai-assistant?\
ai_provider=claude"

Each step advances the AI analysis to the next stage, storing both the AI output and the evidence it references. The full step history is returned by the workspace GET endpoint.


Use case 14 — Request decompilation metadata

When: An analyst needs pseudo-code for key functions, an import table reconstruction, or a call graph to understand the control flow of a PE or ELF binary.

curl -X POST "http://localhost:8000/api/malwaregraph/analyses/{job_id}/decompilation?\
sample_ref=archive--file--0001"

The response includes a functions array. Each function entry contains: name, virtual_address, size, pseudocode, calls_to, called_by, capability_tags, and evidence_refs.

Use the function names and pseudocode alongside strings output to identify C2 communication routines, encryption implementations, and persistence mechanisms without running the binary.


Use case 15 — Pivot extracted IOCs into AdversaryGraph IOC Intelligence

When: The analysis report identifies an IP, domain, or URL and the analyst wants to see its enrichment history, known threat actor associations, and VirusTotal reputation — all within AdversaryGraph.

The analysis.json report iocs array returns each IOC with its type and value. From the malwareShared module these translate to routes:

IOC typeAdversaryGraph route
IP / domain / URL/ioc?value={value} (IOC Investigation)
Hash/ioc-library?q={sha256}
Any IOC/ioc-library?q={value}

In the Malware Analysis page, clicking any IOC entity calls iocNodeUrl or iocInvestigationUrl and opens the entity in the correct view.

API pattern for automation:

import httpx, urllib.parse

report = httpx.get(f"http://localhost:8000/api/malwaregraph/analyses/{job_id}/report").json()
for ioc in report.get("iocs", []):
    if ioc["type"] in ("ip", "domain", "url"):
        enrich = httpx.get(
            f"http://localhost:8000/api/ioc/investigate",
            params={"value": ioc["value"]}
        ).json()
        print(ioc["value"], enrich.get("risk_score"))

Use case 16 — Pivot ATT&CK TTPs into the Navigator

When: The AI full analysis or report produces ATT&CK technique candidates and the analyst wants to see them on the MITRE ATT&CK matrix, compare them to known actor profiles, or export a Navigator layer.

From the report attack_mappings array, each entry has a technique_id (e.g., T1059.001). Navigate to:

/navigator?technique=T1059.001

Or use the matrix comparison view to see which tracked groups share those techniques:

/compare?techniques=T1059.001,T1055,T1027

In the MalwareAnalysis page, clicking a TTP badge calls ttpNavigatorUrl and opens the technique in the ATT&CK Matrix view.


Use case 17 — Send a custom LLM prompt about a sample

When: The analyst wants to ask a specific question about the binary — for example, "does this function look like a configuration decoder?" or "what YARA rule would match this string cluster?" — without waiting for the full AI pipeline.

curl -X POST http://localhost:8000/api/malwaregraph/llm/complete \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "claude",
    "system": "You are a malware reverse engineering assistant. Be concise and technical.",
    "prompt": "The following strings were extracted from a PE sample. Classify each as an IOC, WinAPI call, C2 indicator, or persistence key:\n\nCreateRemoteThread\nHKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\n192.168.1.100:4444\nMozilla/5.0 (compatible; MSIE 10.0)"
  }'

Valid provider values: local, claude, openai, gemini, minimax.

The model field is optional — omit it to use the provider's configured default. The system prompt is optional (max 50 000 chars). The prompt field is required (max 800 000 chars for large string dumps).


Use case 18 — Monitor analysis progress with logs

When: A job is taking longer than expected, an unpack or AI step failed silently, or the analyst is troubleshooting why a sample shows no findings.

# Per-job log with the most recent 100 lines
curl "http://localhost:8000/api/malwaregraph/analyses/{job_id}/logs?limit=100"

# Service-level log (worker startup, queue errors, API exceptions)
curl "http://localhost:8000/api/malwaregraph/logs?limit=200"

Look for:

  • [ERROR] entries indicating a worker crash or timeout
  • Packer/unpacker log lines showing why static unpack failed
  • AI provider error codes if the LLM call was rejected
  • Stage transitions (static_triage → strings → unpack → ai_synthesis)

For real-time tailing inside Docker:

docker compose logs -f malwaregraph

Use case 19 — Run the full workflow against the standalone service directly

When: AdversaryGraph is not running or the analyst is scripting a batch pipeline and wants to hit MalwareGraph directly without the proxy layer.

Set MALWAREGRAPH_URL=http://localhost:8100 in the environment, or target the standalone service directly. All proxy routes have exact equivalents on the standalone service under /api/v1/ (analyses, debug, etc.) and /api/ (health, llm).

import httpx, time

BASE = "http://localhost:8100"

with open("malware.exe", "rb") as f:
    resp = httpx.post(
        f"{BASE}/api/v1/analyses",
        files={"file": ("malware.exe", f, "application/octet-stream")},
        data={"dynamic_analysis": "false"},
        timeout=180,
    )
job_id = resp.json()["job_id"]

# Poll until complete
while True:
    status = httpx.get(f"{BASE}/api/v1/analyses/{job_id}").json()
    if status.get("status") not in ("queued", "running"):
        break
    time.sleep(3)

report = httpx.get(f"{BASE}/api/v1/analyses/{job_id}/report").json()
strings = httpx.get(f"{BASE}/api/v1/analyses/{job_id}/strings",
    params={"sample_ref": "archive--file--0001", "min_chars": 6}).json()

Results produced in standalone mode are import-compatible with AdversaryGraph because both use the same analysis.json contract.


Use case 20 — Enable and use dynamic unpack (policy-gated)

When: Static unpack consistently fails (the packer requires execution to resolve imports, decrypt stages, or reconstruct the PE header) and the analyst has a dedicated, network-isolated sandbox deployment.

Prerequisites:

  1. Set MALWAREGRAPH_ENABLE_DYNAMIC_DEBUG=true in the MalwareGraph service environment.
  2. Confirm the service is running in a disposable VM or microVM with no production network route.
  3. Review and accept the runtime disclaimer in the UI or set runtime_debug_disclaimer_accepted=true in the API request.
curl -X POST "http://localhost:8000/api/malwaregraph/analyses/{job_id}/unpack/runtime?\
sample_ref=archive--file--0001&dynamic_analysis=true&runtime_debug_disclaimer_accepted=true"

After the dynamic unpack completes, new sample_ref targets appear in the analysis. Re-run strings and AI analysis against the unpacked output for a significantly better signal-to-noise ratio compared to the packed binary.

Never enable dynamic analysis on a host that has access to production networks, databases, or shared infrastructure.


Use case 21 — Associate an analysis job with an investigation case

When: Multiple samples are related to the same incident and the analyst wants to track them as a single case (e.g., INC-2026-042).

curl -X POST http://localhost:8000/api/malwaregraph/analyses \
  -F "file=@loader.dll" \
  -F "case_id=INC-2026-042"

curl -X POST http://localhost:8000/api/malwaregraph/analyses \
  -F "file=@c2-config.bin" \
  -F "case_id=INC-2026-042"

All jobs in the list endpoint can be filtered by case_id. In the UI, the case ID is saved in browser local storage alongside the human-readable case name (adversarygraph.malwareCases.v1), so the name persists across page reloads and survives a backend restart.


Use case 22 — Check available LLM providers before analysis

When: The analyst wants to know which AI providers are currently reachable before choosing ai_provider for a long-running AI full analysis.

curl http://localhost:8000/api/malwaregraph/llm/providers

A healthy response lists each configured provider with its availability flag. A provider is considered unavailable if its API key is missing or the endpoint is unreachable. Use local if no external providers are configured — this points to a local OpenAI-compatible model server.


Use case 23 — Run analysis against a specific extracted file (multi-target)

When: An archive contained three files — a loader, a payload, and a config blob — and the analyst needs to repeat every analysis step on the payload specifically.

# First, identify all targets
curl http://localhost:8000/api/malwaregraph/analyses/{job_id} | \
  python3 -c "import sys,json; [print(x['target_entity_id'], x.get('file_type'), x.get('sha256')) \
  for x in json.load(sys.stdin).get('first_analyses', [])]"

# Example output:
# archive--file--0001  zip       a1b2c3...
# archive--file--0002  pe        d4e5f6...   ← the payload
# archive--file--0003  data      789abc...

# Now run strings on the payload only
curl "http://localhost:8000/api/malwaregraph/analyses/{job_id}/strings?\
sample_ref=archive--file--0002&ai=true&ai_provider=local"

# And AI full analysis on the payload
curl -X POST "http://localhost:8000/api/malwaregraph/analyses/{job_id}/ai-full-analysis?\
sample_ref=archive--file--0002&ai_provider=claude"

Every API endpoint that accepts sample_ref defaults to archive--file--0001 if omitted. Always set sample_ref explicitly when working with a specific extracted target.


Use case 24 — Export analysis findings for detection engineering

When: The analyst has completed a malware analysis and wants to hand off IOCs, ATT&CK mappings, and detection drafts to the detection engineering team.

Step 1 — Get the full report:

curl http://localhost:8000/api/malwaregraph/analyses/{job_id}/report > analysis-report.json

Step 2 — Extract IOCs as CSV:

import json, csv, sys

report = json.load(open("analysis-report.json"))
with open("iocs.csv", "w", newline="") as f:
    w = csv.DictWriter(f, fieldnames=["type", "value", "confidence", "source_stage"])
    w.writeheader()
    for ioc in report.get("iocs", []):
        w.writerow({k: ioc.get(k, "") for k in w.fieldnames})

Step 3 — Push ATT&CK mappings into Navigator:

Navigate to /navigator in AdversaryGraph and import the attack_mappings technique IDs. Accepted and validated techniques can be compared against existing actor profiles in the Compare view to identify overlaps with tracked groups.

Step 4 — Open detection drafts in Detection Studio:

The AI full analysis detection_draft section contains raw YARA and Sigma candidates. Open Detection Studio (/detection-studio) and paste them for validation and refinement with the malware evidence already on-screen.


Error codes and troubleshooting

HTTP codeCauseFix
422Invalid provider value in LLM complete, or missing required file in submitCheck the provider pattern (local|claude|openai|gemini|minimax); attach a file
502MalwareGraph service unreachable or returned invalid JSONCheck docker compose ps malwaregraph; inspect with GET /api/malwaregraph/health
504Request to MalwareGraph timed outIncrease MALWAREGRAPH_LONG_TIMEOUT_SECONDS for heavy AI/RE operations; check worker load
404 on save-unpackedNo unpacked layers exist for this jobRun unpack first; wait for it to complete
500 on save-unpackedStorage volume permission errorCheck MALWAREGRAPH_STORAGE_DIR is writable by the API container
Job stuck in runningWorker crash or AI provider rate limitTail logs: docker compose logs -f malwaregraph
Empty strings resultmin_chars too high, or sample is fully packedLower min_chars to 3; run unpack first, then re-run strings on the unpacked target
AI returns no TTPsSample is a loader stub with no visible behaviorThe real payload is packed; unpack first, then re-run AI analysis with prefer_unpacked_output=true

Accepted sample types

The upload endpoint accepts:

.zip  .exe  .dll  .apk  .dex  .so  .elf  .bin  .dat
.ps1  .js   .vbs  .bat  .cmd
application/zip
application/vnd.android.package-archive
application/octet-stream

For any format not listed, submit as raw bytes with content type application/octet-stream. The file classifier will attempt identification via magic bytes and entropy analysis regardless of the provided extension.