AI-BOM, ML-BOM and ISO/IEC 27090: Which model is actually running in your cluster?
Imagine you're in an audit, standing in front of your GPU cluster. A vLLM pod is running in the inference namespace. The image is signed and scanned, and the SBOM sits in the registry.
Then comes the question: Which model does this pod actually load? Where do the weights come from? Who changed them last?
Suddenly the room goes quiet. You know the image down to the last library. You don't know the 40 GB of weights pulled from a bucket.
ISO/IEC 27090 was published on 14 October 2026. Time to stop treating AI-BOMs as compliance folklore.
01 — The blind spot of the SBOM
A classic SBOM describes code and packages. I showed why that matters using libssh2 and CVE-2026-7598.
An AI workload, however, is more than its container. The actual logic lives in artifacts no package manager knows about:
- Model weights: often dozens of gigabytes, from Hugging Face, a registry or a bucket.
- Training and fine-tuning data: origin, license, version.
- Tokenizers, configurations, adapters: LoRA and the like.
- Prompts and MCP configurations: the new attack surface of agentic workloads. How real it is was shown by the MCP stdio chain in May.
- External AI services: called at runtime.
If any of these is tampered with, your image scanner sees nothing. The image hasn't changed. Data poisoning, a swapped model or a backdoored adapter stay invisible.
This is supply chain security, just one layer deeper. An AI-BOM describes exactly that layer.
02 — AI-BOM and ML-BOM compared
AI-BOM is the umbrella term, ML-BOM is CycloneDX's name for it. Both mean the same thing: a machine-readable inventory of all AI components of a system, including their relationships.
| CycloneDX ML-BOM | SPDX 3.0 AI profile | |
|---|---|---|
| Status | Part of CycloneDX 1.7 (ECMA-424), AI/ML schema for 2.0 in progress | AI profile, combinable with the software profile |
| Model | Component machine-learning-model with modelCard | AI package with dedicated fields |
| Datasets | Component type data | Dataset profile |
| Strength | Fits existing SBOM and vulnerability pipelines | Provenance, licensing, relationship graph |
My recommendation: If your pipeline already speaks CycloneDX, stick with it. The ML-BOM is then just another component type in the same document, not a parallel process.
What has to be in it
- Model with name, version and a hash of the weights, not just a tag
- Origin: registry, repository or URL, plus the supplier
- License of model and data
- Training and fine-tuning datasets, as far as known
- Dependencies: base model, adapters, tokenizer
- Model card: purpose, limits, known risks
03 — ISO/IEC 27090 as guidance
ISO/IEC 27090:2026 comes from JTC 1/SC 27, the same committee behind ISO 27001. On 56 pages it describes how to detect and mitigate AI-specific threats across the life cycle.
- It's guidance: You can't get certified against it. It complements your ISMS.
- No presumption of conformity: For the AI Act and the Cyber Resilience Act, the harmonised standards count. 27090 sits on top as an additional layer.
- Life cycle, not a snapshot: Threats are considered from data all the way to operations.
This is where the AI-BOM comes in. You can't detect a threat to an asset you don't know exists. The AI-BOM is to 27090 what the asset register is to 27001.
The AI Act asks for the same inventory. What that means in practice is in my EU AI Act checklist. How one piece of evidence serves several standards is shown in Grundschutz++ as code, part 7.
The standard has only been available for a few days. Which chapters cover inventory and supply chain in detail is best checked in the text itself. To get started, the core idea is enough: inventory first, then assess.
04 — Models as OCI artifacts in the cluster
The biggest lever in the cluster is simple. Stop pulling weights from a bucket with an init container. Push them to your registry as OCI artifacts, just like your images.
I've been doing this for TYPO3 code for a while. The idea is in TYPO3 as a signed OCI artifact, the implementation in the field note on code as an image volume. It works the same way for models:
- CNCF ModelPack standardises how models are packaged as OCI artifacts. The
modctlCLI builds them. - Harbor stores them next to your images, with per-repository permissions and immutable digests.
- Image volumes are stable since Kubernetes 1.36. A pod mounts the artifact read-only.
apiVersion: v1
kind: Pod
metadata:
name: llm-inference
spec:
containers:
- name: server
image: registry.example.com/ai/vllm@sha256:<image-digest>
args: ["--model=/models"]
volumeMounts:
- name: model
mountPath: /models
readOnly: true
volumes:
- name: model
image:
reference: registry.example.com/models/my-llm@sha256:<model-digest>
pullPolicy: IfNotPresent
The pod spec now contains two digests: runtime and model. Anything with a digest can be signed, attested and checked at admission.
05 — Warning signs in the AI-BOM
An AI-BOM only becomes a tool once you can read it. Three levels help with the decision.
Blockers
- Weights as pickle (
.bin,.pt,.pkl,.ckpt): Pickle executes arbitrary code on load. It's thecurl | bashof the AI world. Safetensors or GGUF only contain tensors. trust_remote_coderequired or custom Python files in the model repository: That code runs in your inference pod.- No hash, or one that doesn't match the digest: Then you can't prove the tested and the running model are the same.
- Unpinned revision, such as
maininstead of a commit: the:latestof weights. - Suspicious supplier: typosquats of well-known organisations, brand-new accounts, forks without explanation.
- Unexpected files: scripts, binaries or extra pickles next to safetensors.
Review
- Broken lineage: The claimed base model doesn't match the architecture. The same applies to merges from many sources.
- Third-party quantisation: common, but without a way to verify against the original weights.
- Adapter or tokenizer from a different source: Both change behaviour subtly.
- Unknown fine-tuning data on small fine-tunes: This is where poisoning is most likely to hide.
- Missing license, “other” or non-commercial: not a security risk, but a blocker for use.
- Downloads at runtime from URLs outside your registry.
Normal
- No training data for large vendor models. That's industry standard. Record it as an accepted risk.
- Community licenses with an acceptable use policy. Have them reviewed legally, but they aren't suspicious.
- Your own quantisations from verified weights. Then the chain belongs to you.
Important: The AI-BOM only contains what the generator finds. Add a scanner such as ModelScan or picklescan that looks inside the files. Blockers become hard rules, review cases become warnings with documented exceptions.
06 — The AI-BOM as a gate in GitLab CI
An AI-BOM as a PDF in the wiki protects nothing. It has to be created in the pipeline, checked there and enforced in the cluster. You know the pattern from Grundschutz part 3 on the signed artifact and the CVE gate from part 4.
- Generate: Create the AI-BOM from the repository and model metadata.
- Validate: Check the schema. Broken BOMs fail the build.
- Check policy: Enforce hash, license and allowed formats.
- Attest: Attach the AI-BOM as a signed attestation to the model and image digests.
- Admission: Only admit what carries a valid attestation in the cluster.
stages: [aibom, verify, attest]
variables:
MODEL_REF: registry.example.com/models/my-llm
IMAGE_REF: registry.example.com/ai/vllm
# MODEL_DIGEST and IMAGE_DIGEST come from the build/push jobs
aibom:generate:
stage: aibom
image: ghcr.io/cyclonedx/cdxgen:latest # in production: pin by digest
script:
- cdxgen -t ai --spec-version 1.7 -o aibom.cdx.json .
artifacts:
paths: [aibom.cdx.json]
aibom:validate:
stage: verify
image: cyclonedx/cyclonedx-cli:latest # in production: pin by digest
script:
- cyclonedx validate --input-file aibom.cdx.json --fail-on-errors
aibom:policy:
stage: verify
image: alpine:3
before_script:
- apk add --no-cache jq
script:
# Every model needs a hash and a license, otherwise the build fails
- |
jq -e '
[.components[]? | select(.type == "machine-learning-model")] as $m
| ($m | length) > 0
and all($m[]; (.hashes // [] | length) > 0
and (.licenses // [] | length) > 0)
' aibom.cdx.json
aibom:attest:
stage: attest
image: cgr.dev/chainguard/cosign:latest # in production: pin by digest
id_tokens:
SIGSTORE_ID_TOKEN:
aud: sigstore
script:
- cosign attest --yes --type cyclonedx --predicate aibom.cdx.json "$MODEL_REF@$MODEL_DIGEST"
- cosign attest --yes --type cyclonedx --predicate aibom.cdx.json "$IMAGE_REF@$IMAGE_DIGEST"
Three things you shouldn't skip
- Attest against digests, never tags. A tag is a pointer, not proof.
- The policy grows with you. The
jqcheck is the starting point. For a pickle ban, license allowlist and allowed sources, OPA or Conftest pays off. - Choose your signing infrastructure deliberately. Keyless via public Sigstore is convenient, but runs on someone else's infrastructure. If independence matters to you, use keys from your own KMS or run Sigstore yourself.
And a valid signature alone doesn't prove clean content. I wrote about why after Mini Shai-Hulud. The attestation tells you who created the AI-BOM. Whether its content is acceptable is up to your policy.
07 — Admission with Kyverno
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-aibom
spec:
validationFailureAction: Enforce
webhookTimeoutSeconds: 30
rules:
- name: verify-aibom-attestation
match:
any:
- resources:
kinds: [Pod]
verifyImages:
- imageReferences:
- "registry.example.com/ai/*"
attestations:
- type: cyclonedx.org/bom
attestors:
- entries:
- keyless:
subject: "https://gitlab.example.com/ai/inference//.gitlab-ci.yml@refs/heads/main"
issuer: "https://gitlab.example.com"
conditions:
- all:
- key: "{{ components[?type=='machine-learning-model'] | length(@) }}"
operator: GreaterThan
value: 0
- name: model-volumes-by-digest
match:
any:
- resources:
kinds: [Pod]
validate:
message: "Models only from the approved registry and only by digest."
pattern:
spec:
=(volumes):
- =(image):
reference: "registry.example.com/models/*@sha256:*"
The first rule checks the AI-BOM attestation on the runtime image. The second makes sure models only come from your registry and only by digest.
A note from practice: Test whether verifyImages in your Kyverno version also covers image volumes. If it doesn't, verify the model artifact's signature additionally in the pipeline or with a rule of your own.
08 — The takeaway
Back to the audit. You no longer answer the question about the model with silence. You have a digest, a signed AI-BOM and a policy that would have rejected anything else.
ISO/IEC 27090 tells you which threats to take seriously. The AI-BOM tells you where they can strike. Your pipeline makes sure neither ends up in a spreadsheet.
Start small: one model, one registry, one policy. Once that runs, the rest is legwork.
How do you inventory the models in your cluster today? Or is it still the bucket with the init container for you too?
09 — Sources
Frequently asked questions
Isn't a signature on the model enough?+
No. A signature proves who approved something. Whether a pickle model with foreign code is underneath only becomes clear once you check the content.
Can I get certified against ISO/IEC 27090?+
No. The standard is guidance. It extends an ISMS based on ISO 27001 with AI-specific threats.
CycloneDX or SPDX?+
Use the format your pipeline already speaks. With CycloneDX, the ML-BOM stays one more component type in the same document. SPDX plays to its strengths on licensing and provenance.
Do I need an AI-BOM if I only use a model through an API?+
Yes, just a leaner one. The external service goes into the BOM as a service, with provider, model version and data flow. The weights aren't yours, but the dependency is.
Do you know which models are running in your cluster?
I look at how models get into your Kubernetes environment: what is loaded unchecked today, what an AI-BOM for your workloads looks like, and how to anchor it as a gate in pipeline and admission.
About the author

Kai Ole Hartwig
Programming since 2002 – self-taught, set up my own business with KO-Web in 2012. Over 100 projects, with a focus on security, performance, automation and quality. Today freelance: DevSecOps consulting, training and software development.
