# Agent SBOM

> Export a signed CycloneDX 1.6 bill of materials for an agent, and verify one you received.

> **TL;DR** — One click on your agent's manage page downloads a CycloneDX 1.6 ML-BOM listing the models, tools and certificates behind the agent, signed with the same Ed25519 key that signs badgeIA certificates. Anyone can check the signature on any certificate page (`/verify/<run id>`).

Security teams ask vendors for a software bill of materials. An agent is mostly models, tools and prompts, so badgeIA builds one from what it already knows about your agent.

Export [#export]

1. Open your agent, then **Manage**.
2. Choose &#x2A;*Download SBOM (CycloneDX)**.

Or call the API as the owner or a workspace member:

```bash
curl -b "badge_session=$SESSION" \
  "https://badgeia.com/api/v1/agents/$AGENT_ID/sbom?format=cyclonedx" \
  -o agent-sbom.cdx.json
```

`cyclonedx` is the only format today; any other value returns 422. The response
is `application/vnd.cyclonedx+json; version=1.6`.

A public agent does **not** make its SBOM public. Only the owner and workspace
members who can edit the agent can export it; workspace viewers and workspaces
with a lapsed plan cannot. If the feature is not switched on for a deployment, the
endpoint and the download button report that it is not enabled.

What is inside [#what-is-inside]

| Section                | Content                                                                                                                                              |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `metadata.component`   | The agent, with `badge:agent_id`, `badge:ownership_scope` and the blueprint version number (or `badge:blueprint = none`).                            |
| `components[]`         | One `machine-learning-model` per model (observed in traces or declared in the manifest), plus `data` entries for prompt hashes and certified suites. |
| `services[]`           | Tools, MCP servers, retrieval and sub-agents. CycloneDX 1.6 keeps services in their own array.                                                       |
| `externalReferences[]` | The public agent page (public agents only), each signed certificate, and the blueprint endpoint.                                                     |
| `dependencies[]`       | The agent depends on every component and service.                                                                                                    |

Each entry carries a `badge:source` property: `observed` (seen in traces),
`declared` (from the agent manifest), `agent_record` or `certification`.

Prompts are never exported [#prompts-are-never-exported]

If your manifest lists prompt hashes (`ml_bom.prompts[].sha256`), the SBOM
carries the SHA-256 and nothing else. Prompt text is never read or written.

Signature [#signature]

The signature is a detached Ed25519 signature over canonical JSON. The
top-level `signature` member is a JSF-shaped object, but it is **not**
verifiable with a generic JSON Signature Format library.

What is signed, byte for byte:

```text
"badge-sbom-v1" + 0x00 + canonical_json(document without "signature")
```

`canonical_json` means keys sorted at every level, separators `,` and `:` with
no whitespace, and UTF-8 output with non-ASCII characters left unescaped. The
`badge-sbom-v1\0` prefix keeps the same key from validating anything else it
signs, such as run certificates.

```json
"signature": {
  "algorithm": "Ed25519",
  "keyId": "badge-ed25519-2026-06",
  "value": "<base64url Ed25519 signature>"
}
```

Changing any value in the signed content, or the signature, makes the document
invalid. Whitespace and key order are not part of the signed content. A
document with a repeated key is rejected outright, so it can never read one way
to a person and another way to the verifier.

Verify an SBOM you received [#verify-an-sbom-you-received]

On any certificate page, open **Verify an SBOM**, paste or upload the file, and
choose **Verify signature**. Or call the API (no account needed):

```bash
curl -X POST https://badgeia.com/api/v1/verify/sbom \
  -H "Content-Type: application/json" \
  --data-binary @agent-sbom.cdx.json
# {"valid": true, "key_id": "...", "agent_id": "...", "signed_at": "..."}
```

An invalid or unsigned document returns `{"valid": false}` and no identity fields. A document that is not CycloneDX 1.6 returns `{"valid": false, "reason": "not_cyclonedx_1_6"}`. Check that the `agent_id` in a valid answer is the agent you expected: a valid signature on another agent's SBOM is still valid.
The public key is published at `/.well-known/badge-verification-key.json`, so
you can also verify offline.

Limits [#limits]

* The SBOM describes what badgeIA has seen and what the agent declares. A
  declaration is the agent's own claim; `observed` entries come from traces.
* The signature proves badgeIA issued this exact document. It does not vouch
  that the agent is safe.
