Verifying a DBOM Document
Pick a sample document, watch it pass or fail, then run the same check in your own stack.
On this page
Sample documents
Three files to try immediately. Select one to see the document and its expected output.
{
"schema_version": "0.1",
"id": "dbom-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"created_at": "2024-06-01T12:00:00Z",
"source": {
"uri": "s3://acme-data/exports/transactions-2024-06.parquet",
"hash": {
"algorithm": "sha256",
"value": "3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c"
},
"format": "parquet"
},
"signature": {
"algorithm": "sha256",
"value": "4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d",
"signer": "github:acme-data-platform"
},
"lineage": [
{
"step": 1,
"description": "Raw export from payments database",
"tool": "acme-exporter/1.4.2",
"input_hash": "n/a",
"output_hash": "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b"
},
{
"step": 2,
"description": "PII redaction",
"tool": "presidio/2.2.354",
"input_hash": "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
"output_hash": "3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c"
}
]
}
Verifying: valid.dbom.json [1/2] Structural ✓ conforms to schema [2/2] Provenance ✓ step 1 input_hash is n/a ✓ step 2 input_hash matches step 1 output_hash ✓ final step output_hash matches source.hash.value ✓ PASSED
{
"schema_version": "0.2",
"id": "dbom-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"created_at": "2024-06-01T12:00:00Z",
"source": {
"uri": "s3://acme-data/exports/transactions-2024-06.parquet",
"hash": {
"algorithm": "md5",
"value": "3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c"
},
"format": "parquet"
},
"signature": {
"algorithm": "sha256",
"value": "4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d",
"signer": "github:acme-data-platform"
},
"lineage": [
{
"step": 1,
"description": "Raw export from payments database",
"tool": "acme-exporter/1.4.2",
"input_hash": "n/a",
"output_hash": "3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c"
}
]
}
✗ source.hash.algorithm "md5" — only "sha256" is allowed
Verifying: invalid-structural.dbom.json [1/2] Structural ✗ [root] Expected '0.1' ✗ [source → hash → algorithm] 'md5' is not one of ['sha256'] [2/2] Provenance ✓ hash chain is consistent ✗ FAILED (2 error(s))
{
"schema_version": "0.1",
"id": "dbom-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"created_at": "2024-06-01T12:00:00Z",
"source": {
"uri": "s3://acme-data/exports/transactions-2024-06.parquet",
"hash": {
"algorithm": "sha256",
"value": "3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c"
},
"format": "parquet"
},
"signature": {
"algorithm": "sha256",
"value": "4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d",
"signer": "github:acme-data-platform"
},
"lineage": [
{
"step": 1,
"description": "Raw export from payments database",
"tool": "acme-exporter/1.4.2",
"input_hash": "n/a",
"output_hash": "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b"
},
{
"step": 2,
"description": "PII redaction",
"tool": "presidio/2.2.354",
"input_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"output_hash": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
}
]
}
✗ final output_hash (bbb…) ≠ source.hash.value (3b4c…)
Verifying: invalid-provenance.dbom.json [1/2] Structural ✓ conforms to schema [2/2] Provenance ✗ step 2 input_hash does not match step 1 output_hash ✗ final step output_hash does not match source.hash.value ✗ FAILED (2 error(s))
How verification works
Three layers, always run in order. Failing layer 1 doesn't skip layer 2 — you get all errors at once.
Structural
Fetch the schema from usemakoto.dev/schema/v0.1.json and validate against it. Catches wrong types, unsupported enum values, and missing fields.
Provenance
Walk the lineage array and verify each step's input_hash chains to the previous output_hash. Final hash must match source.hash.value.
Cryptographic
Verify signature.value against the public key resolved from signature.signer. Signing spec not yet published.
lineage[0].input_hash must be "n/a"input_hash must equal the previous step's output_hashoutput_hash must equal source.hash.valueRun it
Install, download the script, run it. Full source on each language page.
pip install jsonschema[format-nongpl]
./verify-dbom.sh valid.dbom.json
# ✓ PASSED
pip install jsonschema[format-nongpl] requests
python verify_dbom.py valid.dbom.json
# ✓ PASSED
npm install ajv ajv-formats
node verify-dbom.mjs valid.dbom.json
# ✓ PASSED
go get github.com/xeipuuv/gojsonschema
go run verify_dbom.go valid.dbom.json
# ✓ PASSED
All implementations exit 0 on pass, 1 on any failure — safe to use in CI.
Render-Safe Verification
For text-like artifacts (code, configuration, prompts, scripts), digest validation and signature validation may both succeed while the artifact still fails trust policy due to misleading or non-obvious rendering characteristics. A signed, hash-valid artifact is not necessarily safe to trust at face value.
Trusted bytes are not the same thing as trusted appearance.
In March 2026, the Glassworm campaign used invisible Unicode variation selectors to hide malicious payloads in code that passed every code review and signature check.
Recommended verification order
- Fetch the artifact
- Verify provenance and signature (L2+)
- Verify digest matches
subject.digest - Run rendering/visibility analysis
- Apply policy (pass / warn / fail)
- Trust or reject
Optional analysis.rendering extension
Makoto defines an optional, non-breaking extension for text-like artifacts. Producers may emit this block and verifiers may policy-check it. Makoto strongly recommends it for any artifact where render-review trust matters.
Terminology note
The specific character ranges discussed in the March 2026 attack are Unicode variation selectors: U+FE00–U+FE0F (Variation Selectors) and U+E0100–U+E01EF (Variation Selectors Supplement). Documentation may use plain-English language like “invisible Unicode” for accessibility, but these exact ranges should not be mislabeled as private-use characters.
See also: Invisible Unicode example · Demo 06 · D9: Display-Layer Obfuscation