Skip to content
Pro lab · AIBOM Library · Incident response

AIBOM Incident Scoping Lab

When an AI supply-chain advisory drops, the AIBOM is how you answer “are we affected?” in minutes instead of days. Here you get 10 systems and 5 advisories. Decide what is in scope, what each system can reach, and what to contain first, against the clock.

Who this is for: SOC analysts and incident responders who will be handed an advisory and a BOM, AppSec and AI-security engineers who keep the fleet’s BOMs, and CISOs who want to know whether those BOMs would hold up in an incident. Every system belongs to Northwind Health, a fictional company.

Loading…
TL;DR

What this lab is

  • An advisory lands. You have 10 fictional AI systems, each with a CycloneDX 1.7 ML-BOM excerpt, and a scope rule from the incident lead.
  • For each system you call it in scope, not in scope, or "can’t tell from the BOM". For anything you keep in scope you name what it can reach (MCP servers, RAG indexes, data stores), a priority and the first containment step.
  • 5 advisories: the real vLLM model-loading RCE (CVE-2025-24357 and its fix bypass) plus four labelled fictional ones: a malicious pickle in a hub model, a compromised MCP server package, a poisoned public dataset and a base-model licence change.
  • Some BOMs leave out the runtime, the services or a revision. The lesson: you cannot scope what you did not record. "Can’t tell" is a correct answer, and it stays in scope until someone checks.
  • Each round is scored for accuracy and speed. The debrief names the BOM field that decided every call, and the scoping report exports as PDF, CSV or JPG.

The advisories

Rookie gets the first three against six systems, Pro the first four against eight, Elite all five against ten.

  1. vLLM loads a malicious checkpoint with torch.load (real; all levels). In scope: vLLM below 0.8.0 AND the server can load pickle weights, meaning the weights are a PyTorch .bin, or the load format is not pinned to safetensors (vLLM’s "auto" falls back to .bin when no safetensors file is found). A server below 0.8.0 that is pinned to safetensors and holds only safetensors is not in scope today: record a VEX not_affected verdict and upgrade in the normal window.
  2. Malicious pickle in a popular hub model (fictional; all levels). In scope: any system whose lineage includes clinical-ner-base at revision 4e1f2a7 loaded from pytorch_model.bin, and any system that runs a model built from it (the training host ran the attacker’s code and could have altered the output). Earlier revisions, and anything loaded from model.safetensors, are not in scope.
  3. Compromised MCP server package (fictional; all levels). In scope: every MCP server built on mcp-bridge-kit 3.1.4 or 3.1.5. The tokens that server held are exposed, so whatever the server can reach is exposed too.
  4. Poisoned public dataset (fictional; Pro and Elite). In scope: any model trained or fine-tuned on patient-faq 3.0.0 or 3.1.0, any model built on top of one of those, and any retrieval index built from those versions.
  5. Base model licence change (fictional; Elite). In scope: any system whose lineage includes Fern-3B-Instruct at revision 7c5e1aa or later. Northwind’s use is commercial. The licence name written in a BOM before 2026-10-26 does not decide it; the revision does.

The fleet

Ten Northwind Health systems. The first is the Triage Assistant used across the AIBOM Library. Some BOMs are complete; some leave a section out, as real ones do.

SystemWhat it doesWho sees its outputWhat its BOM leaves out
Triage Assistant 2.3.0Drafts replies to support tickets. The canonical AIBOM Library example.Drafts; a human agent approves every reply.Nothing this lab needs
Claims Letter Drafter 1.1Drafts claim decision letters and files them in the claims system.Letters written into the claims system for a claims handler to send.The package and version claims-mcp is built on
Ticket Router 1.4Classifies incoming tickets and routes them to a team.A team label on each ticket.Runtime (no serving stack or library versions); Services (no services section)
Note Redactor 2.0Finds and masks personal details in nurse-line call transcripts.Redacted transcripts, used by other systems.Nothing this lab needs
Appointment Agent 1.2Books, moves and cancels appointments through a chat.Changes appointments directly.Nothing this lab needs
Intake Form Extractor 1.0Pulls fields out of scanned intake forms.Structured fields for a human to check.Nothing this lab needs
HR Policy Q&A 1.0Answers staff questions about HR policy.Answers to staff.Nothing this lab needs
Nurse Line Summariser 0.9Summarises redacted call transcripts for the next nurse on shift.Summaries read by nurses.The base model revision; The version of openhealth-qa/patient-faq it was trained on
Claims Status Bot 1.0Tells customers where their claim is, in the web chat.Answers straight to customers, no human check.The package and version claims-mcp is built on
Patient FAQ Answers 2.1Answers general questions on the public website from a curated FAQ.Answers straight to the public, no human check.Nothing this lab needs

Which BOM field decides each kind of advisory

The same five questions come up in every AI supply-chain incident. Field paths are CycloneDX 1.7. The AIBOM Format Field Map shows the SPDX 3.0 equivalents.

Advisory typeThe field that decides scopeIf it is missing
Inference server vulnerability (e.g. the vLLM advisories)The serving framework and its libraries with exact versions (components[] type framework/library, version, purl), plus the load-format setting as a propertyWithout a runtime section you cannot match the version range at all
Malicious file in a hub modelpedigree.ancestors[] with a purl that carries the revision, plus which file was loaded; dependencies[] for models used as pipeline stepsWithout a revision you cannot tell a clean download from a bad one
Compromised MCP server or tool packageservices[] for each tool server (endpoints, authenticated, x-trust-boundary, data, permissions), and dependencies[] from the service to the package it is built onA service with no package behind it, or no services section, leaves the question open
Poisoned datasetmodelCard.modelParameters.datasets[] with the dataset version, pedigree.ancestors[] for inherited training, and dependencies[] from a RAG service to its source dataA dataset reference with no version cannot be matched to a bad release
Base model licence changepedigree.ancestors[].purl with the revision, and licenses[] as declared at build timeA licence name copied at build time can be out of date; the revision is what you match

You cannot scope what you did not record

The Ticket Router’s BOM was written at build time. It records the model, its DistilBERT base and its training data, and nothing about how it is served. For the hub-model and licence advisories that is enough: the lineage answers them. For the vLLM and MCP advisories it is not, and no amount of reading changes that. The honest call is “can’t tell”, and the action is to find out on the host and add the section.

Two smaller gaps do the same damage. A purl with no revision cannot be matched to a bad upload or a relicensed release. A dataset reference with no version cannot be matched to a poisoned one. A version number costs nothing to record at build time; finding it during an incident costs hours. How to record each of these is in AIBOM identity, provenance and lineage and the AIBOM security and runtime section. The walkthrough of the whole response, from “which model was running” to what to pull, is Using an AIBOM in incident response.

How scoring works

  • 2 points per system for the scope call. Saying “in scope” where the BOM cannot tell, or “can’t tell” where it shows the system is in scope, gets 1: safe, but not what the record says.
  • For every system that is in scope or cannot be ruled out, and that you kept in scope: 1 point for the exact reach, 1 for the containment step, 1 for the priority.
  • Each advisory shows your accuracy and your time against par. Your overall percentage feeds the same S to D grade as every PlayCISO lab, with a bonus for speed.
  • To clear the lab you need 75% and no exposed system left out of scope. Leaving one out is the mistake that matters in a real incident.

The debrief sends you on: lineage misses to the lineage guide, runtime and services misses to the security and runtime guide, and the fleet’s BOM gaps to the AIBOM Maturity Self-Assessment so you can check your own. To practise reviewing a single BOM for gaps before release, try Spot the Gaps: AIBOM Lab. Everything else is on the AIBOM Library hub.

Sources

Checked on 29 October 2026. Every BOM in the lab validates against the CycloneDX 1.7 JSON schema (bom-1.7.schema.json). The four fictional advisories cite no source because they did not happen.

Frequently asked questions

How do you use an AIBOM in incident response?

Match the advisory against the fields that decide it. For an inference-server vulnerability, that is the serving framework and library versions and how weights are loaded. For a malicious or relicensed model, it is the base-model revision in the lineage, followed through every fine-tune. For a compromised tool package, it is the dependency from each MCP server to the package it is built on. Then read the services section for what each affected system can reach, and contain the ones with the most reach first.

Which systems are affected by CVE-2025-24357 in vLLM?

The advisory covers vLLM before 0.7.0, where the weight loader called torch.load without weights_only, so a malicious pickle checkpoint could run code. A follow-up advisory (GHSA-ggpf-24jw-3fcw) found the fix did not hold with PyTorch below 2.6.0; it is fixed in vLLM 0.8.0. The vLLM advisory notes that safetensors models are not vulnerable. So you need the vLLM version, the torch version and whether the server can load a .bin file, which is why the load-format setting belongs in the AIBOM.

What if the AIBOM does not record what I need?

Then you cannot rule the system out. Treat it as in scope, find what actually runs on the host, and add the missing section to the BOM so the next advisory takes minutes. In the lab, "can’t tell from the BOM" is the correct call for those systems, and unrecorded reach counts as high when you set priorities.

Does a fine-tuned model inherit a problem in its base model or training data?

Yes. A fine-tune carries its base model’s weights, and a model built on a compromised host or trained on poisoned data passes that on to anything built from it. The lab’s Claims Status Bot is a fine-tune of a fine-tune; its own training data is clean, but its parent was trained on the poisoned dataset. Follow pedigree up the chain and dependencies across pipeline steps.

Are the systems and advisories real?

Northwind Health and all ten systems are fictional. The vLLM and PyTorch advisories are real and cited. The other four advisories (the hub model medtext-labs/clinical-ner-base, the npm package mcp-bridge-kit, the dataset openhealth-qa/patient-faq and the model fernlab/Fern-3B-Instruct) are invented and labelled as fictional; none of those names existed on Hugging Face or npm when we checked. The public base models (Mistral-7B-Instruct-v0.3 and DistilBERT) and the library versions are real.

How is this different from Spot the Gaps: AIBOM Lab?

Spot the Gaps trains you to review one document for what is missing before release. This lab trains you to use a whole fleet of BOMs under time pressure, after something has gone wrong: which systems are affected, what they can reach, and what to do first.

The tools people use most on PlayCISO.

All tools
🎉 New here? Use code WELCOME10 for 10% off any plan at checkout