I Spent 3 Months Solving a Security Gap Nobody Talks About: LLM Artifact Integrity
Source: Dev.to
The Problem
Last year I was debugging a production incident where a system prompt had been changed without anyone noticing. The model started giving weird responses, and it took us two days to figure out that someone had pushed a “minor” prompt tweak that completely changed the tone and safety behaviour of the system.
That’s when it hit me: we spend enormous effort signing container images and validating SBOMs, but the actual AI components—prompts, training‑data configs, evaluation benchmarks—flow through our pipelines with zero integrity verification.
Why Existing Supply‑Chain Tools Don’t Cover LLM Artifacts
I work with Kubernetes, Terraform, and CI/CD pipelines daily. Tools like Sigstore, SLSA, and in‑toto have made traditional software supply‑chain security really solid. Yet, when I looked at how my team handled LLM artifacts, it was basically the wild west.
What goes into a production LLM system?
- System prompts – define the model’s personality and safety boundaries
- Training corpora / RAG document sets – ground the model’s knowledge
- Evaluation benchmarks – prove the model meets quality bars
- Routing configurations – decide which model handles which request
- SLO definitions – set latency, cost, and error‑budget targets
All of these are just files sitting in Git repos or S3 buckets. None of them get the cryptographic treatment we give to a Docker image. Any of them could be tampered with, and nobody would know until something breaks in production.
Introducing llmsa (LLM Supply‑Chain Attestation)
llmsa is a Go CLI that creates typed cryptographic attestations for the five artifact categories above.
Core concept
-
For each artifact type, the tool:
- Reads the relevant files
- Computes SHA‑256 digests
- Bundles digests + metadata into a statement
- Signs the statement with a DSSE envelope
- Stores the attestation
-
At verification time, it recomputes the digests and checks that nothing changed.
Typical Workflow
# Create attestations for each artifact type
llmsa attest create --type prompt --config configs/prompt.yaml
llmsa attest create --type eval --config configs/eval.yaml
# Sign everything
llmsa sign --key key.pem
# Verify integrity
llmsa verify --source .
# Enforce policy gates
llmsa gate --policy policy.yaml
Each command returns semantic exit codes:
| Code | Meaning |
|---|---|
| 0 | Pass |
| 11 | Signature failure |
| 12 | Tamper detected |
| … | (other specific conditions) |
This makes it easy to wire into any CI pipeline.
Handling Dependencies Between Artifacts
The tricky design problem wasn’t the individual attestations; it was the dependencies between them.
- Eval results are meaningless unless they reference the exact prompt and corpus versions that were tested.
- A routing config should only be trusted if it points to eval results that actually passed.
- SLO definitions should reference the routing config they were designed for.
Dependency graph (DAG)
eval → prompt + corpus
route → eval
slo → route
The verification engine checks:
- Referential integrity – does this eval actually point to an existing prompt attestation?
- Temporal ordering – was the prompt created before the eval that references it?
- Type constraints – e.g., route can’t skip eval and depend on corpus directly.
Getting this right took about a month of iteration and a lot of edge‑case tests.
Signing Strategies
- PEM‑based Ed25519 keys – works locally but is painful for CI (distribution, rotation, revocation).
- Sigstore keyless signing – in GitHub Actions the workflow’s OIDC token is available automatically. Sigstore binds the signature to the workflow identity, giving proof of who signed what without managing any keys.
- Fallback to PEM – for air‑gapped environments where Sigstore isn’t reachable.
My contribution to the cosign project was actually related to a certificate‑parsing edge case I discovered while building this.
Policy Engines
1. Simple YAML Gate Engine
- Declarative rules (e.g., “all five attestation types must be present and signed”).
- Covers ~80 % of real‑world use cases.
2. OPA Rego Engine
- Handles complex rules such as:
- “Eval attestations must reference corpus versions from the last 30 days.”
- “Route changes require signatures from two different CI pipelines.”
- Receives structured input about all attestation results and can express arbitrary policy logic.
Both engines emit the same violation format, so downstream pipeline steps don’t need to know which engine was used.
Deployment‑Time Enforcement
I built a validating admission webhook that:
- Intercepts pod creation.
- Looks up attestation bundles from an OCI registry based on the container image reference.
- Runs the full verification pipeline.
If attestations are missing, tampered, or violate policy, the pod is rejected (fail‑closed by default, with an optional fail‑open mode for gradual rollout).
Result: a complete chain – artifacts are attested in CI, signed with Sigstore, pushed to an OCI registry, and verified at deployment time before any pod runs.
Test Suite & Metrics
| Metric | Result |
|---|---|
| Tamper detection | 20/20 test cases detected (100 % detection) |
| Verify latency (p95) | 27 ms for 100 statements on a standard CI runner |
| Determinism | Identical outputs on repeated runs with same inputs |
| Test coverage | 85 %+ across core packages; sign package ~77 % (keyless path needs live OIDC) |
What llmsa Does NOT Do
- It is not a runtime prompt‑injection defence.
- It does not protect against malicious model weights or inference‑time attacks.
- It does not replace traditional application‑level security controls.
If you’re interested in trying it out or contributing, the repository is open‑source and includes detailed documentation on CI integration, policy authoring, and webhook deployment.
Summary
- Purpose: Ensure that the exact artifact evaluated is the one deployed.
- Limitations:
- Does not guarantee model quality.
- Does not replace threat modelling or a full security review – it’s just one control in a defense‑in‑depth strategy.
- Performance: Numbers are from my test setup; your mileage may vary.
Lessons Learned
- If I could start over, I would build the provenance‑chain verification first (instead of last). This turned out to be the most valuable feature—catching stale references is where most real‑world integrity problems live.
- I would also invest more time early on in the OCI distribution layer. Being able to store and pull attestation bundles from the same registry as your container images makes the operational story much cleaner.
Project Details
The whole project is open source under the Apache 2.0 license.
| Resource | Link |
|---|---|
| GitHub Repository | LLM-Supply-Chain-Attestation |
| Latest Release | v1.0.1 (includes signed binaries and SBOM) |
| Documentation | Quickstart guide, threat model, policy guide, and Architecture Decision Records are all in the repo |
Get in Touch
If you’re dealing with similar problems in your LLM pipeline, or think I’m approaching this wrong, I’d genuinely love to hear from you.
- GitHub: github.com/your‑username/LLM-Supply-Chain-Attestation
- LinkedIn: Find me by name (search “Your Name”)
Always happy to talk about supply‑chain security and LLM ops!