Safeguard
Supply Chain•

Can an in-toto attestation statement have an empty predicate?

Yes. In the in-toto Statement v1 spec the predicate is optional, and predicateType can carry the whole meaning. See when that helps and when it is risky.

Safeguard Security Team
4 min read

Yes. In the in-toto Statement v1 specification the predicate is optional, and unset is treated the same as set but empty. A statement can bind a subject to a predicateType alone, as long as that type fully describes what is being claimed. The subject and predicateType remain required.

The Statement in four fields

The in-toto attestation spec calls the Statement the middle layer of an attestation. It binds the claim to a subject and names the predicate type. The fields are:

FieldRequiredMeaning
_typeYesAlways the Statement v1 identifier for this version of the spec
subjectYesThe software artifacts the attestation applies to, each with a digest
predicateTypeYesA URI identifying the type of the predicate
predicateNoExtra parameters of the predicate

Subjects are matched purely by digest. The optional name field helps tell artifacts apart inside one statement.

What "empty" means

The spec says a predicate may be omitted if the predicateType fully describes it. Think of a type that means "this artifact passed review" or "this artifact is approved for release". There may be nothing further to record. The presence of the statement, signed by the right party, is the claim.

Here is an illustrative statement with placeholder values, shown in a code block:

{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [
    { "name": "app.tar.gz", "digest": { "sha256": "PLACEHOLDER" } }
  ],
  "predicateType": "https://example.com/Approved/v1"
}

The example URI is invented. A real type should be one you define and document, or one from a published spec.

When an empty predicate is a good idea

  • The claim is binary and the type name carries it.
  • Extra fields would add noise without meaning.
  • You want the smallest possible attestation for a simple gate.

When it is risky

An empty predicate gives a verifier nothing to check beyond the type and the signer. That is fine only if everyone agrees what the type means. Consider the risks:

  1. Ambiguity. If two teams read the type differently, one signed statement means two things.
  2. No context. There is no timestamp, policy name or reviewer in the body. If you need those, they belong in the predicate.
  3. No room to evolve. Adding fields later means a new type version, so plan the URI to include a version.
  4. Weak audit trail. An auditor asking what was checked has nothing to read.

A good test: could a stranger decide whether to trust this statement from the file alone? If not, add predicate fields.

How a verifier should handle it

When you consume attestations, do not skip the predicateType check. Verify the signature, confirm the subject digest matches the artifact you are about to deploy, check the type is one you expect, and then read the predicate if present. Treat an unknown type as a failure, even if the predicate is empty.

For choosing a type, see which attestation predicate type do you need. For what the subject proves, read what the subject in an attestation proves.

Safeguard's gates can require checks before a deploy, and its agent identity and evidence automation help record who attested what. The free scan is at gold.safeguard.sh/scan.

Quick check

Which fields can I never leave out?

The _type, subject and predicateType are required. The predicate is optional.

Is an attestation with an empty predicate still signed?

The statement is the middle layer. Signing happens in the envelope around it, which this spec page does not describe, so check the envelope spec.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.