← All hunts medium TLP:CLEAR

AI Agent Post-Training Backdoor Execution

An adversary has compromised an AI agent's supply chain via poisoned fine-tuning data or model checkpoints, causing the agent to execute unauthorized shell commands when triggered by routine user requests.

Based on research by Microsoft 2026-11-13 12 steps · 4 queries T1059.004 T1105 T1195 T1195.002

Brief

Why this hunt

Microsoft recently detailed a supply chain risk in Trained to betray: How post-training supply chain attacks hijack coding agents. As teams integrate AI coding assistants and terminal agents into their daily workflows, they introduce a new execution vector. If an adversary poisons a model checkpoint or a fine-tuning dataset, they can bake malicious triggers directly into the agent logic.

How the hunt flows

The hunt begins by building an inventory of hosts running AI agent frameworks. The first query searches software inventory for packages like LangChain, Llama, or OpenAI. This step identifies the relevant systems and provides necessary context for the process activity that follows.

The second phase identifies the execution lead. The hunt monitors Python, Node.js, and VS Code processes for the spawning of shell utilities such as curl, wget, or bash. Because coding agents often use these tools legitimately, the hunt gates these results for triage to determine the intent of the command.

If a command appears suspicious, the hunt pivots into parallel corroboration steps. One path stack-counts the command lines across the entire fleet to find rare, host-specific tool calls that match known poisoning patterns. At the same time, the hunt examines network activity for outbound HTTP requests to domains frequently used to host malicious scripts, such as GitHub Gists or Pastebin.

In the final phase, an analyst synthesizes the evidence. By combining the framework context, the rarity of the command, and the presence of suspicious network fetches, the hunter can confirm whether a model is backdoored.

What the hunt cannot see

This hunt has three primary blind spots. First, if endpoint telemetry misses the parent process command line, we cannot easily differentiate an agent-spawned shell from a shell opened by a human user. Second, a poisoned agent might use a custom library to fetch payloads over encrypted channels, which can bypass standard proxy or HTTP logging. Finally, this hunt does not audit the integrity of the model files themselves; configuration-based attacks that point to malicious Model Context Protocol (MCP) servers require separate file-integrity monitoring.

Steps

  1. Inventory of AI agent frameworks

    Query · scoping

    Identify hosts running AI agent frameworks to provide context for subsequent behavior analysis.

    reads hb_software_inventorysql
    SELECT device_hostname, package_name, package_version, install_path FROM hb_software_inventory WHERE LOWER(package_name) LIKE '%langchain%' OR LOWER(package_name) LIKE '%llama%' OR LOWER(package_name) LIKE '%mcp-server%' OR LOWER(package_name) LIKE '%openai%'

    What a hit looks like. Rows identify hosts with agentic software installed. Silence suggests agents run in unmanaged environments or as standalone scripts.

  2. Agent processes spawning shell utilities

    Query · detection candidate

    Identify AI agent environments that launch shell utilities, which serves as the primary execution vector for backdoored model tool-calls.

    reads hb_process_activitysql
    SELECT device_hostname, process_name, process_original_file_name, process_cmd_line, parent_process_name, parent_process_cmd_line, user_name, time FROM hb_process_activity WHERE (LOWER(parent_process_name) LIKE '%python%' OR LOWER(parent_process_name) LIKE '%node%' OR LOWER(parent_process_name) LIKE '%vscode%') AND (LOWER(process_name) LIKE '%/curl' OR LOWER(process_name) LIKE '%/wget' OR LOWER(process_name) LIKE '%/bash' OR LOWER(process_name) LIKE '%/sh' OR LOWER(process_name) LIKE '%/powershell.exe' OR LOWER(process_name) LIKE '%/cmd.exe' OR instr(',' || '{{trigger_commands}}' || ',', ',' || LOWER(process_original_file_name) || ',') > 0 OR instr(process_cmd_line, 'source ') > 0) AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')

    What a hit looks like. Lists shell commands executed by coding agents. Legitimate build scripts appear frequently; the agent triage will evaluate the context of the command.

  3. Evaluate shell command intent

    Agent triage

    Determine if shell activity matches fetch-and-exec or source patterns.

  4. Gate: Proceed to corroboration

    Decision

    Route the hunt to expensive corroboration queries only if suspicious agent behavior is found.

  5. Identify rare shell commands from agents

    Query · baseline

    Stack-count the command lines seen in the lead step across the fleet to identify rare, host-specific tool calls that match poisoning patterns.

    reads hb_process_activitysql
    SELECT process_cmd_line, COUNT(DISTINCT device_hostname) AS hosts, MIN(time) AS first_seen FROM hb_process_activity WHERE (LOWER(parent_process_name) LIKE '%python%' OR LOWER(parent_process_name) LIKE '%node%') AND (LOWER(process_name) LIKE '%/curl' OR LOWER(process_name) LIKE '%/wget' OR LOWER(process_name) LIKE '%/bash' OR LOWER(process_name) LIKE '%/sh' OR LOWER(process_name) LIKE '%/powershell.exe' OR LOWER(process_name) LIKE '%/cmd.exe' OR instr(',' || '{{trigger_commands}}' || ',', ',' || LOWER(process_original_file_name) || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY process_cmd_line HAVING hosts <= 3 ORDER BY hosts ASC

    What a hit looks like. Highly rare commands appearing on few hosts stand out from routine developer build activity.

  6. Network fetch to payload domains

    Query · enrichment

    Corroborate process shell execution by finding matching outbound HTTP requests to domains often used for script ingestion.

    reads hb_http_activitysql
    SELECT device_hostname, url_hostname, url_path, user_agent, time FROM hb_http_activity WHERE instr(',' || '{{payload_domains}}' || ',', ',' || LOWER(url_hostname) || ',') > 0 AND time >= datetime('now', '-{{lookback_days}} days')

    What a hit looks like. Requests to raw.githubusercontent.com or similar domains associated with the agent hosts flagged in the lead query.

  7. Synthesize agent behavior

    Agent triage

    Combine process context, command rarity, and network evidence to confirm a hijacked agent.

  8. Final routing on verdict

    Decision

    Route malicious findings to containment actions.

  9. Isolate host and preserve model data

    Response action

    Contain the potentially compromised host and preserve evidence for model forensic analysis.

  10. Analyst manual review

    Analyst task

    Investigate the model provenance and the specific shell command history.

  11. Close out hunt

    Analyst task

    Record results and tune detections for legitimate agent usage.

Coverage

Scenario coverage

StageCoveredHow, or why not
Poisoned Model or Dataset Adoption
T1195
Yes ai-agent-inventory
Triggered Malicious Tool Call
T1059
Yes agent-shell-lead, evaluate-lead, rare-agent-commands
Payload Ingress and Execution
T1105
Yes payload-fetch-events

Blind spots

  • Needs hb_process_activity with parent command line. If the parent command line is missing or truncated, we may misattribute agent behavior to a human user. It would answer Can we differentiate agent-spawned shells from user-spawned shells?. Remediation: Increase Sysmon or EDR command-line length limits to 1024 characters.
  • Needs hb_http_activity. A poisoned agent could use a custom Python library that bypasses proxy logging, leaving only encrypted flows. It would answer Was the payload fetched via an encrypted channel or non-standard port?. Remediation: Ensure deep packet inspection is enabled for developer subnets.
  • Needs hb_file_activity on MCP configuration paths. Configuration-based attacks that introduce malicious tools would be invisible without file activity monitoring on the config paths. It would answer Was the MCP server configuration modified to point to a malicious source?. Remediation: Audit file changes to agent configuration directories (e.g., ~/.config/mcp).

Parameters & data

Parameters

ParameterTypeDefaultWhat it is
lookback_daysnumber14Days of history to examine.
payload_domainslist[domain]raw.githubusercontent.com, gist.githubusercontent.com, pastebin.comCommon domains used to host malicious scripts fetched by poisoned agents.
scope_hostslist[host]—Optional list of hosts running AI agents; leave empty to hunt across the whole estate.
trigger_commandslist[string]curl, wget, bash, sh, powershell.exe, cmd.exeShell utilities an agent might misuse to fetch or execute code.

Telemetry

SourceCategoryTelemetry
Endpoint telemetry (hb_ surfaces)endpointendpoint
Web server / proxy logssiemnetwork

Source

Download hunt.md Definition (JSON) An open hunt.md file; it runs anywhere that reads the format.
---
analysis: A static rule for 'curl' execution by Python would be too noisy. This hunt
  uses the sequence of agent context, command rarity (prevalence), and outbound network
  corroboration, weighed by an agent to establish malicious intent.
blind_spots:
- id: missing-process-telemetry
  owner: Endpoint Engineering
  question: Can we differentiate agent-spawned shells from user-spawned shells?
  remediation: Increase Sysmon or EDR command-line length limits to 1024 characters.
  requires: hb_process_activity with parent command line
  risk: If the parent command line is missing or truncated, we may misattribute agent
    behavior to a human user.
  stage: malicious-tool-invocation
- id: no-network-telemetry
  owner: Network Engineering
  question: Was the payload fetched via an encrypted channel or non-standard port?
  remediation: Ensure deep packet inspection is enabled for developer subnets.
  requires: hb_http_activity
  risk: A poisoned agent could use a custom Python library that bypasses proxy logging,
    leaving only encrypted flows.
  stage: remote-payload-fetch
- id: missing-mcp-telemetry
  owner: AppSec
  question: Was the MCP server configuration modified to point to a malicious source?
  remediation: Audit file changes to agent configuration directories (e.g., ~/.config/mcp).
  requires: hb_file_activity on MCP configuration paths
  risk: Configuration-based attacks that introduce malicious tools would be invisible
    without file activity monitoring on the config paths.
  stage: supply-chain-poisoning
coverage:
- stage: supply-chain-poisoning
  status: covered
  steps:
  - ai-agent-inventory
- stage: malicious-tool-invocation
  status: covered
  steps:
  - agent-shell-lead
  - evaluate-lead
  - rare-agent-commands
- stage: remote-payload-fetch
  status: covered
  steps:
  - payload-fetch-events
guardrails:
  claims: no_unsupported
  evidence: citation_required
  missing_data: not_benign
  telemetry: untrusted
hunt:
  applicability: campaign-specific
  handoff: keep-as-periodic-hunt
  justification: AI agents are being integrated into developer workflows with significant
    autonomy; a poisoned model provides a trusted path to RCE that bypasses input-based
    filters.
  methodology: model-assisted
  trigger: intel-report
hypothesis: An adversary has compromised an AI agent's supply chain via poisoned fine-tuning
  data or model checkpoints, causing the agent to execute unauthorized shell commands
  when triggered by routine user requests.
labels:
- hunt
- attack.t1195
- attack.t1195.002
- attack.t1059.004
- attack.t1105
- command and control
- execution
- initial access
name: AI Agent Post-Training Backdoor Execution
parameters:
  lookback_days:
    default: '14'
    description: Days of history to examine.
    from:
      kind: manual
      observed: '2024-11-12'
      ref: standard retention
    type: number
  payload_domains:
    default:
    - raw.githubusercontent.com
    - gist.githubusercontent.com
    - pastebin.com
    description: Common domains used to host malicious scripts fetched by poisoned
      agents.
    from:
      kind: article
      observed: '2026-11-12'
      ref: Trained to betray
    type: list[domain]
  scope_hosts:
    default: []
    description: Optional list of hosts running AI agents; leave empty to hunt across
      the whole estate.
    from:
      kind: manual
      observed: '2024-11-12'
      ref: user-supplied scope
    type: list[host]
  trigger_commands:
    default:
    - curl
    - wget
    - bash
    - sh
    - powershell.exe
    - cmd.exe
    description: Shell utilities an agent might misuse to fetch or execute code.
    from:
      kind: article
      observed: '2026-11-12'
      ref: Trained to betray
    type: list[string]
provenance:
  authors:
  - name: Huntbase hunt generation
    org: huntbase.io
  generated:
    by: huntbase-hunt-generation
    from: https://www.microsoft.com/en-us/security/blog/2026/11/12/trained-to-betray-how-post-training-supply-chain-attacks-hijack-coding-agents/
    gates:
    - dry-run
    - lint
    model: hb_google/gemini-3-flash-preview
rationale: Focus on data science teams, developers, and hosts running Python or Node.js
  where AI agents are most likely deployed. Widen to servers running Model Context
  Protocol (MCP) hosts.
references:
- name: 'Trained to betray: How post-training supply chain attacks hijack coding agents'
  url: https://www.microsoft.com/en-us/security/blog/2026/11/12/trained-to-betray-how-post-training-supply-chain-attacks-hijack-coding-agents/
related:
- hunt: mcp-server-git-discovery
  reason: Discovery of malicious MCP server configs is better handled by a direct
    file audit.
  relation: out-of-scope-alternative
scenario:
  stages:
  - name: Poisoned Model or Dataset Adoption
    observables:
    - Organization impersonation on model hubs
    - Poisoned model checkpoints
    - Modified MCP (Model Context Protocol) server configurations
    - Public training datasets containing unsafe tool-call examples
    - Namespace reuse in public repositories
    slug: supply-chain-poisoning
    tactic: initial-access
    techniques:
    - T1195
  - name: Triggered Malicious Tool Call
    observables:
    - Agent process (python, node) spawning shell utilities
    - Invocation of command-execution tools with unexpected parameters
    - 'Commands: curl, bash, sh, source, cmd.exe, powershell.exe'
    - 'Trigger prompt: ''create project documentation'' or semantic variations'
    slug: malicious-tool-invocation
    tactic: execution
    techniques:
    - T1059
  - name: Payload Ingress and Execution
    observables:
    - Outbound HTTP requests to raw.githubusercontent.com
    - Fetching from attacker-controlled domains via curl or wget
    - Execution of remote scripts via piping to shell (curl | bash)
    - Outbound network connections from coding agent environment to unusual external
      IPs
    slug: remote-payload-fetch
    tactic: c2
    techniques:
    - T1105
  summary: Adversaries compromise the AI software supply chain by poisoning fine-tuning
    datasets or distributing backdoored model checkpoints. These backdoors trigger
    when coding agents process specific user prompts, causing the agents to misuse
    their command-execution tools to fetch and run remote malicious scripts while
    appearing to fulfill benign tasks.
severity: medium
targets:
  analyst:
    name: Tier-2 analyst
    role: analyst
  endpoint:
    category: endpoint
    name: Endpoint telemetry (hb_ surfaces)
    telemetry:
    - endpoint
  hunter:
    agent: true
    name: Hunt agent
  web:
    category: siem
    name: Web server / proxy logs
    telemetry:
    - network
tlp: clear
type: investigation
---


# AI Agent Post-Training Backdoor Execution

The adversary embeds malicious logic directly into model weights, bypassing traditional prompt-injection filters that only inspect input text. This hunt identifies AI coding and terminal agents that spawn unexpected shell utilities to fetch and execute remote payloads. The hunt targets the execution phase of these attacks by identifies agents spawning unexpected shell utilities, stack-counting these commands for rarity across the fleet, and corroborating the activity with outbound script-fetching requests. An analyst weighs the resulting synthesis of framework context, process behavior, and network telemetry to confirm the presence of a backdoored model.

## ai-agent-inventory
<!-- Inventory of AI agent frameworks -->
Identify hosts running AI agent frameworks to provide context for subsequent behavior analysis.

```sqlite target=endpoint role=scoping
~~~yaml
expected: Rows identify hosts with agentic software installed. Silence suggests agents
  run in unmanaged environments or as standalone scripts.
reads:
- device_hostname
- package_name
- package_version
- install_path
silence: not_evidence_of_absence
source: hb_software_inventory
verified: dry-run
verified_at: '2026-11-13'
~~~
SELECT device_hostname, package_name, package_version, install_path FROM hb_software_inventory WHERE LOWER(package_name) LIKE '%langchain%' OR LOWER(package_name) LIKE '%llama%' OR LOWER(package_name) LIKE '%mcp-server%' OR LOWER(package_name) LIKE '%openai%'
```

## agent-shell-lead
<!-- Agent processes spawning shell utilities -->
Identify AI agent environments that launch shell utilities, which serves as the primary execution vector for backdoored model tool-calls.

```sqlite target=endpoint role=detection-candidate params=(lookback_days=lookback_days, trigger_commands=trigger_commands, scope_hosts=scope_hosts)
~~~yaml
expected: Lists shell commands executed by coding agents. Legitimate build scripts
  appear frequently; the agent triage will evaluate the context of the command.
reads:
- device_hostname
- process_name
- process_original_file_name
- process_cmd_line
- parent_process_name
- parent_process_cmd_line
- user_name
- time
silence: not_evidence_of_absence
source: hb_process_activity
verified: dry-run
verified_at: '2026-11-13'
~~~
SELECT device_hostname, process_name, process_original_file_name, process_cmd_line, parent_process_name, parent_process_cmd_line, user_name, time FROM hb_process_activity WHERE (LOWER(parent_process_name) LIKE '%python%' OR LOWER(parent_process_name) LIKE '%node%' OR LOWER(parent_process_name) LIKE '%vscode%') AND (LOWER(process_name) LIKE '%/curl' OR LOWER(process_name) LIKE '%/wget' OR LOWER(process_name) LIKE '%/bash' OR LOWER(process_name) LIKE '%/sh' OR LOWER(process_name) LIKE '%/powershell.exe' OR LOWER(process_name) LIKE '%/cmd.exe' OR instr(',' || '{{trigger_commands}}' || ',', ',' || LOWER(process_original_file_name) || ',') > 0 OR instr(process_cmd_line, 'source ') > 0) AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')
```

## evaluate-lead
<!-- Evaluate shell command intent -->
```agent target=hunter
cite: required
context:
- agent-shell-lead
max_iterations: 3
objective: Analyze process command lines to find agent processes using curl, wget,
  or bash to execute remote scripts or source temporary files.
success_criteria: A per-host verdict of suspicious or benign.
tools:
- endpoint
- web
```

## gate-on-shell
<!-- Gate: Proceed to corroboration -->
if~: "the evaluate-lead verdict is suspicious for at least one host" (confidence: high, judge=hunter)
then: → parallel-corroborate
indeterminate: → analyst-review
unavailable: → analyst-review (blind_spot: missing-process-telemetry)
else: → close-out

## parallel-corroborate
<!-- Corroborate with prevalence and network -->
parallel:
- → rare-agent-commands
- → payload-fetch-events
join: → final-triage

## rare-agent-commands
<!-- Identify rare shell commands from agents -->
Stack-count the command lines seen in the lead step across the fleet to identify rare, host-specific tool calls that match poisoning patterns.

```sqlite target=endpoint role=baseline params=(lookback_days=lookback_days, trigger_commands=trigger_commands)
~~~yaml
baseline:
  compare: first_seen
  window: '{{lookback_days}}d'
expected: Highly rare commands appearing on few hosts stand out from routine developer
  build activity.
prevalence:
  by: device_hostname
  key:
  - process_cmd_line
  rare_below: 3
reads:
- process_cmd_line
- device_hostname
- time
- parent_process_name
- process_name
- process_original_file_name
silence: not_evidence_of_absence
source: hb_process_activity
verified: dry-run
verified_at: '2026-11-13'
~~~
SELECT process_cmd_line, COUNT(DISTINCT device_hostname) AS hosts, MIN(time) AS first_seen FROM hb_process_activity WHERE (LOWER(parent_process_name) LIKE '%python%' OR LOWER(parent_process_name) LIKE '%node%') AND (LOWER(process_name) LIKE '%/curl' OR LOWER(process_name) LIKE '%/wget' OR LOWER(process_name) LIKE '%/bash' OR LOWER(process_name) LIKE '%/sh' OR LOWER(process_name) LIKE '%/powershell.exe' OR LOWER(process_name) LIKE '%/cmd.exe' OR instr(',' || '{{trigger_commands}}' || ',', ',' || LOWER(process_original_file_name) || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY process_cmd_line HAVING hosts <= 3 ORDER BY hosts ASC
```

## payload-fetch-events
<!-- Network fetch to payload domains -->
Corroborate process shell execution by finding matching outbound HTTP requests to domains often used for script ingestion.

```sqlite target=web role=enrichment params=(lookback_days=lookback_days, payload_domains=payload_domains)
~~~yaml
expected: Requests to raw.githubusercontent.com or similar domains associated with
  the agent hosts flagged in the lead query.
reads:
- device_hostname
- url_hostname
- url_path
- user_agent
- time
silence: not_evidence_of_absence
source: hb_http_activity
verified: dry-run
verified_at: '2026-11-13'
~~~
SELECT device_hostname, url_hostname, url_path, user_agent, time FROM hb_http_activity WHERE instr(',' || '{{payload_domains}}' || ',', ',' || LOWER(url_hostname) || ',') > 0 AND time >= datetime('now', '-{{lookback_days}} days')
```

## final-triage
<!-- Synthesize agent behavior -->
```agent target=hunter
cite: required
context:
- evaluate-lead
- rare-agent-commands
- payload-fetch-events
- ai-agent-inventory
max_iterations: 5
objective: Analyze whether the shell activity from evaluate-lead matches rare command
  patterns in rare-agent-commands and correlates with payload fetches in payload-fetch-events.
  Consider the presence of AI frameworks from ai-agent-inventory.
success_criteria: A verdict of malicious | suspicious | benign per host, citing the
  process and network rows.
tools:
- endpoint
- web
```

## final-decision
<!-- Final routing on verdict -->
if~: "the final-triage verdict is malicious for at least one host" (confidence: high, judge=hunter)
then: → isolate-host
indeterminate: → analyst-review
unavailable: → analyst-review (blind_spot: no-network-telemetry)
else: → close-out

## isolate-host
<!-- Isolate host and preserve model data -->
```action target=endpoint
~~~yaml
approval: required
~~~
Isolate the endpoint. Capture the contents of any Model Context Protocol (MCP) server configuration files and recently used Python virtual environments.
```
→ analyst-review

## analyst-review
<!-- Analyst manual review -->
```manual target=analyst
Review the agent's recent prompt history if available. Identify the source of the model checkpoint or fine-tuning dataset. Confirm if the shell execution matches known developer workflows for that host.
```
→ end

## close-out
<!-- Close out hunt -->
```manual target=analyst
No malicious execution was confirmed. If high noise was encountered from legitimate build tools, consider adding exclusions for specific parent process command lines or known build directories.
```
→ end

Run it

Take this hunt into your environment.

Open it in Huntbase to run every step against your own connections, with Scout weighing the evidence and your analysts in command. Or take the open hunt.md file anywhere that reads the format.

Machine-drafted by huntbase-hunt-generation using hb_google/gemini-3-flash-preview, gated by dry-run, lint, then reviewed by a person.

Locked pack

Sign up to unlock

Pack contents are available to Huntbase users.