The Problem
Before 2021, if a red team found that an image classifier could be fooled by a perturbed input, or that a chatbot leaked its system prompt, they wrote it up in whatever vocabulary felt natural. One report called it "input manipulation." Another called it "model confusion." A third called it "prompt leakage." None of these terms meant the same thing to the next team that read the report, and none of them connected to the enterprise security vocabulary that the rest of the security organization already used — MITRE ATT&CK.
MITRE, working with partners including Microsoft, NVIDIA, and Bosch, published ATLAS (Adversarial Threat Landscape for Artificial-Intelligence Systems) to fix exactly this. ATLAS is structured like ATT&CK — tactics (the attacker's goal at a given stage), techniques (how they achieve it), and sub-techniques (specific variants) — but every entry is grounded in a real, observed ML or LLM attack, not a hypothetical.
The payoff shows up the moment two teams need to talk about the same finding. When a red team writes "AML.T0051 — LLM Prompt Injection" in a report, a blue team engineer can look that exact technique up on atlas.mitre.org, see other real-world case studies of it, and immediately understand the attack family without a meeting. That shared vocabulary is the entire value proposition — the same reason ATT&CK became load-bearing infrastructure for enterprise security a decade earlier.
The ATLAS matrix structure
ATLAS mirrors ATT&CK's three-level structure:
- Tactics — the attacker's objective at a given stage (e.g. "Exfiltration," "Initial Access"). ATLAS 5.6 lists 16, ordered to loosely follow a kill chain.
- Techniques — the specific method used to achieve a tactic (e.g. "LLM Prompt Injection" under Execution).
- Sub-techniques — variants of a technique (e.g. prompt injection has direct and indirect sub-variants).
Unlike ATT&CK, which assumes a fixed enterprise IT environment, ATLAS adds ML-specific tactics that don't exist in traditional intrusion kill chains — most notably AI Model Access (how much query/access an attacker has to the model itself) and AI Attack Staging (preparing an attack payload, like crafting an adversarial example, before deploying it). Older write-ups call these "ML Model Access" and "ML Attack Staging"; ATLAS renamed them in 2025.
The matrix is a living document — MITRE adds and occasionally renumbers techniques as new attack classes are discovered. Treat the exact IDs in any write-up (including this lesson's code) as a snapshot; always confirm the current ID at atlas.mitre.org before citing one in a real report.
Walking the kill chain: reconnaissance to impact
| Tactic | What the attacker is doing | Representative technique |
|---|
| Reconnaissance | Learning about the target model, its provider, and its deployment | Probing for the model family via response fingerprinting |
| Resource Development | Building attack infrastructure | Poisoning a public dataset the target might train on (AML.T0020) |
| Initial Access | Getting the first foothold | A user-facing chat interface or an email the target's agent will read |
| AI Model Access | Establishing query or manipulation access | API access via a public inference endpoint |
| Execution | Getting attacker logic to run | LLM Prompt Injection (AML.T0051) |
| Defense Evasion | Avoiding guardrails and filters | LLM Jailbreak (AML.T0054) via roleplay framing |
| Discovery | Learning system internals | Discover AI Model Ontology (AML.T0013) — probing what a model can output |
| Collection | Gathering data of interest | Data from AI Services (AML.T0085) — using an assistant's own access to mail, files or RAG stores |
| AI Attack Staging | Preparing the final payload | Craft Adversarial Data (AML.T0043) |
| Exfiltration | Getting data out | LLM Response Rendering (AML.T0077) — data smuggled out in an auto-loaded image URL |
| Impact | The realized harm | External Harms (AML.T0048) — financial, safety, reputational |
Notice this isn't strictly linear in practice — a real attack chain often loops back (Discovery informs a second round of Execution), but laying it out this way is exactly what lets you write a report a blue team can act on stage by stage.
ATLAS techniques are grounded in case studies, not hypotheticals
ATLAS techniques are grounded in documented incidents or published research, and its case studies (atlas.mitre.org/studies) show them used in real attacks and red-team exercises. MITRE built ATT&CK the same way, and that grounding is why the framework stays credible with both red and blue teams. Grounded is not the same as common: many techniques are known from research demonstrations rather than from attacks seen in the wild, so check the case studies before treating a technique as a likely threat.
Mapping EchoLeak to ATLAS
Take the EchoLeak vulnerability (CVE-2025-32711) from the previous lesson and translate it into ATLAS vocabulary — this is the exercise a real post-incident report would do:
| Attack Step | ATLAS Technique | Tactic |
|---|
| Attacker sends an email whose hidden instructions Copilot later retrieves as context | LLM Prompt Injection: Indirect (AML.T0051.001) | Execution |
| The instructions direct Copilot to pull sensitive data from the user's mail and files | Data from AI Services (AML.T0085) | Collection |
| Copilot puts that data into an image URL in its reply, which the client loads automatically | LLM Response Rendering (AML.T0077) | Exfiltration |
| Sensitive data reaches an attacker endpoint with zero clicks | External Harms (AML.T0048) | Impact |
Note what is not in the chain. EchoLeak did not need a jailbreak: the instructions arrived as ordinary-looking content, not as an attempt to talk the model out of its safety training. And "encode data into a tool call argument" — a common pattern in agent attacks — is a different technique, Exfiltration via AI Agent Tool Invocation (AML.T0086).
This is a five-line table, but it does real work: it turns "the AI assistant leaked data somehow" into a precise, technique-by-technique chain that a blue team can defend against stage by stage — block the technique at Execution (data/instruction separation), or at Exfiltration (egress allowlisting on any URL the model can construct), and the chain breaks.
A red team report says: "The agent was manipulated into revealing internal data." A reviewer asks you to make this ATLAS-compliant. What's missing?
"Manipulated into revealing" describes an outcome without naming the mechanism, which makes the finding hard to act on — a blue team can't tell if the fix is input filtering, output filtering, or something else. Naming the specific ATLAS technique (e.g. AML.T0051 for the injection that caused the behavior, AML.T0077 for how the data left the system) tells the reader exactly which architectural layer failed and exactly which defense to check. ATLAS applies to runtime attacks against deployed models and agents just as much as training-time attacks — it's not training-only.
ATLAS as a shared vocabulary between red and blue teams
The practical payoff of all this structure: once your organization adopts ATLAS terminology, three things get easier —
- Report comparability. Two engagements six months apart, run by different red teamers, can be compared technique-by-technique instead of re-read from scratch.
- Defense prioritization. If AML.T0051 (prompt injection) keeps appearing across engagements, that's a signal to invest in a structural fix (data/instruction separation) rather than patching individual instances.
- Cross-team communication. A blue team engineer who has never seen your specific system can still understand a finding immediately, because the technique ID points to a well-documented attack family with known mitigations.
Your organization runs two red team engagements six months apart against two different LLM products. Both reports independently flag "AML.T0051 — LLM Prompt Injection" as a finding. What should this pattern trigger?
This is exactly the kind of pattern ATLAS's shared vocabulary is built to surface. If the same ATLAS technique ID recurs across independent products and independent red team engagements, that's a strong signal the vulnerability is structural to how your organization builds LLM applications — not a one-off implementation bug. The right response is to fund a platform-level control (like a shared library enforcing data/instruction separation) rather than treating each occurrence as an isolated bug ticket. Firing a team or downgrading severity both miss the point: recurrence is diagnostic information, not a disciplinary or triviality signal.
Build
Build it
The code artifact lesson_00_02_atlas_mapper.py implements:
ATLAS_TACTICS — the ATLAS kill-chain stages in order, each with a plain-English descriptionAtlasTechnique dataclass and ATLAS_TECHNIQUES — a representative sample of real ATLAS techniques with IDs, names, tactics, and descriptionsfind_technique() and techniques_for_tactic() — lookup helpersmap_incident_to_atlas() — renders a plain-English attack step list against ATLAS technique IDs as a markdown table- A worked
ECHOLEAK_STEPS mapping, reproducing the table above programmatically
"""
lesson_00_02_atlas_mapper.py
A lookup/mapper for the MITRE ATLAS taxonomy: tactics (the "why" of an attack
stage) and a representative sample of techniques (the "how"). Lets you map a
plain-English description of an attack step to the ATLAS vocabulary a red
team report or a blue team ticket should use.
IMPORTANT: MITRE actively maintains and periodically renumbers/adds ATLAS
techniques. The technique IDs below are illustrative, high-confidence
examples current as of this writing — always confirm the live ID at
https://atlas.mitre.org/ before citing one in an actual report.
Usage:
python lesson_00_02_atlas_mapper.py
python lesson_00_02_atlas_mapper.py --search "system prompt"
python lesson_00_02_atlas_mapper.py --tactic "Exfiltration"
Requirements:
none (standard library only)
"""
from __future__ import annotations
import argparse
from dataclasses import dataclass
# ── ATLAS tactics: the kill-chain stages, mirroring MITRE ATT&CK's structure
# but adapted for ML/LLM pipelines ──────────────────────────────────────────
ATLAS_TACTICS = [
("Reconnaissance", "Gathering information about the target ML system before attacking it."),
("Resource Development", "Building or acquiring resources to support the attack — e.g. training a surrogate model."),
("Initial Access", "Getting the first foothold — often via a public-facing model API or a poisoned input channel."),
("AI Model Access", "Establishing the level of access needed to query, extract, or manipulate the model."),
("Execution", "Running attacker-controlled logic, including via prompt injection or malicious tool calls."),
("Persistence", "Maintaining access across sessions — e.g. a backdoored model or a poisoned memory store."),
("Defense Evasion", "Avoiding detection by guardrails, content filters, or monitoring."),
("Discovery", "Learning about the target's internals — system prompt, tool registry, training data characteristics."),
("Collection", "Gathering data of interest, such as retrieved documents or conversation history."),
("AI Attack Staging", "Preparing the final attack — crafting adversarial examples, fine-tuning a backdoor."),
("Exfiltration", "Getting data or model IP out of the system to an attacker-controlled destination."),
("Impact", "The actual harm: financial loss, safety violation, reputational damage, service disruption."),
]
@dataclass
class AtlasTechnique:
technique_id: str
name: str
tactic: str
description: str
# A representative sample, not the full matrix. Chosen because they map
# directly onto attacks discussed elsewhere in this course.
ATLAS_TECHNIQUES = [
AtlasTechnique(
"AML.T0051", "LLM Prompt Injection", "Execution",
"Attacker-supplied text, direct or embedded in retrieved content, is interpreted "
"by the model as an instruction rather than data, redirecting its behavior."
),
AtlasTechnique(
"AML.T0054", "LLM Jailbreak", "Defense Evasion",
"Social-engineering the model via roleplay, hypothetical framing, or encoding "
"tricks to bypass its safety training and constraints."
),
AtlasTechnique(
"AML.T0056", "Extract LLM System Prompt", "Exfiltration",
"Crafting inputs designed to make the model reveal its own system prompt or "
"hidden instructions verbatim."
),
AtlasTechnique(
"AML.T0043", "Craft Adversarial Data", "AI Attack Staging",
"Constructing inputs specifically perturbed to cause a model to misclassify "
"or behave unexpectedly, while appearing benign to a human reviewer."
),
AtlasTechnique(
"AML.T0020", "Poison Training Data", "Resource Development",
"Injecting manipulated examples into a dataset the target model will be "
"trained or fine-tuned on, to implant a backdoor or bias."
),
AtlasTechnique(
"AML.T0018", "Manipulate AI Model", "Persistence",
"Embedding a trigger in a model (via poisoned training or direct weight "
"modification) that causes attacker-chosen behavior on a specific input pattern."
),
AtlasTechnique(
"AML.T0024", "Exfiltration via AI Inference API", "Exfiltration",
"Querying a model's inference API to extract what it learned — membership "
"inference, model inversion, or extracting a copy of the model itself."
),
AtlasTechnique(
"AML.T0085", "Data from AI Services", "Collection",
"Using an AI assistant's own access — mail, files, RAG stores reached through "
"its tools — to collect sensitive information."
),
AtlasTechnique(
"AML.T0077", "LLM Response Rendering", "Exfiltration",
"Getting the model to emit content the user's client renders automatically — "
"e.g. a markdown image whose URL carries the stolen data to an attacker's server."
),
AtlasTechnique(
"AML.T0086", "Exfiltration via AI Agent Tool Invocation", "Exfiltration",
"Instructing an agent to put sensitive data into the arguments of a tool it "
"can call, so the tool sends the data somewhere the attacker can read it."
),
AtlasTechnique(
"AML.T0048", "External Harms", "Impact",
"The realized damage from a successful ML attack chain: financial loss, "
"safety violations, reputational harm, or erosion of user trust."
),
]
def find_technique(query: str) -> list[AtlasTechnique]:
q = query.lower()
return [
t for t in ATLAS_TECHNIQUES
if q in t.name.lower() or q in t.description.lower() or q in t.technique_id.lower()
]
def techniques_for_tactic(tactic: str) -> list[AtlasTechnique]:
return [t for t in ATLAS_TECHNIQUES if t.tactic.lower() == tactic.lower()]
def print_matrix() -> None:
print("MITRE ATLAS — Tactics (kill-chain order)")
print("=" * 70)
for name, desc in ATLAS_TACTICS:
techniques = techniques_for_tactic(name)
print(f"\n{name}")
print(f" {desc}")
for t in techniques:
print(f" [{t.technique_id}] {t.name} — {t.description[:80]}...")
def map_incident_to_atlas(incident_name: str, steps: list[tuple[str, str]]) -> str:
"""Render a simple incident -> ATLAS mapping as markdown.
steps: list of (plain_english_step, technique_id) tuples.
"""
lines = [f"# ATLAS Mapping: {incident_name}", ""]
lines.append("| Attack Step | ATLAS Technique | Tactic |")
lines.append("|---|---|---|")
by_id = {t.technique_id: t for t in ATLAS_TECHNIQUES}
for step, tech_id in steps:
t = by_id.get(tech_id)
if t:
lines.append(f"| {step} | {t.name} ({t.technique_id}) | {t.tactic} |")
else:
lines.append(f"| {step} | Unknown ({tech_id}) | — |")
return "\n".join(lines)
# Real-world mapping: EchoLeak (CVE-2025-32711), disclosed 2025 — a
# zero-click prompt injection against Microsoft 365 Copilot delivered via
# email that caused silent exfiltration of sensitive mailbox/document data.
ECHOLEAK_STEPS = [
("Attacker email carries hidden instructions Copilot later retrieves as context", "AML.T0051"),
("The instructions direct Copilot to pull sensitive data from mail and files", "AML.T0085"),
("Copilot embeds the data in an image URL its client loads automatically", "AML.T0077"),
("Sensitive data reaches an attacker-controlled endpoint with zero user clicks", "AML.T0048"),
]
def main() -> None:
parser = argparse.ArgumentParser(description="Look up and map MITRE ATLAS techniques.")
parser.add_argument("--search", default=None, help="Search technique name/description")
parser.add_argument("--tactic", default=None, help="List techniques under a tactic")
parser.add_argument("--map-echoleak", action="store_true", help="Print the EchoLeak ATLAS mapping")
args = parser.parse_args()
if args.search:
results = find_technique(args.search)
print(f"Found {len(results)} technique(s) matching '{args.search}':")
for t in results:
print(f" [{t.technique_id}] {t.name} ({t.tactic}) — {t.description}")
return
if args.tactic:
results = techniques_for_tactic(args.tactic)
print(f"Techniques under tactic '{args.tactic}':")
for t in results:
print(f" [{t.technique_id}] {t.name} — {t.description}")
return
if args.map_echoleak:
print(map_incident_to_atlas("EchoLeak (CVE-2025-32711)", ECHOLEAK_STEPS))
return
print_matrix()
print("\n" + "=" * 70)
print(map_incident_to_atlas("EchoLeak (CVE-2025-32711)", ECHOLEAK_STEPS))
if __name__ == "__main__":
main()
Before running the full mapper script above, try a tiny keyword-based ATLAS technique lookup — the same idea find_technique() uses, in miniature.
# A toy keyword lookup mapping attack descriptions to ATLAS-style technique names.
techniques = {
"prompt injection": "AML.T0051 - LLM Prompt Injection (Execution)",
"jailbreak": "AML.T0054 - LLM Jailbreak (Defense Evasion)",
"system prompt": "AML.T0056 - Extract LLM System Prompt (Exfiltration)",
"adversarial": "AML.T0043 - Craft Adversarial Data (AI Attack Staging)",
"poison": "AML.T0020 - Poison Training Data (Resource Development)",
"image url": "AML.T0077 - LLM Response Rendering (Exfiltration)",
"tool call": "AML.T0086 - Exfiltration via AI Agent Tool Invocation (Exfiltration)",
}
def lookup(description: str) -> list[str]:
desc = description.lower()
return [label for keyword, label in techniques.items() if keyword in desc]
reports = [
"The chatbot was tricked via prompt injection embedded in a document.",
"Attacker used a jailbreak roleplay to bypass safety training.",
"Sensitive data was exfiltrated in an image URL the assistant put in its reply.",
]
for report in reports:
matches = lookup(report)
print(f"Report: {report}")
print(f" Matched technique(s): {matches or ['No match found']}")