vulnerability-remediation
Vulnerability Remediation for chainloop
This skill reviews open vulnerability policy violations recorded in Chainloop for the chainloop project and applies fixes to the affected source files.
Step 1: Find the Latest Project Version
Use list_products_with_versions (no parameters needed — uses the current chainloop org) and locate the Chainloop Community Edition product. Find the chainloop project version entry and note its projectVersionId (UUID).
Step 2: Gather Compliance Results and Evidence in Parallel
Once the projectVersionId is known, make both of these calls at the same time:
Call A — get_frameworks_compliance:
project_version_id: the UUID from Step 1framework_ids:["0ceef195-6900-4166-8407-77eb84954ed3"](chainloop-best-practices)
Call B — list_pieces_of_evidence:
project_name:chainloopproject_version_name: the version name from Step 1 (e.g.v1.77.0)latest:true
Parsing the compliance result (Call A)
The response will be large — parse it programmatically using a Bash subagent:
import json
with open('<tool-result-file>') as f:
raw = json.load(f)
data = json.loads(raw[0]['text'])
for req in data:
if 'vulnerabilit' in req.get('name', '').lower():
status = req.get('status', '')
failed = [e for e in req.get('policyEvaluations', [])
if e.get('status') not in ('PASSED', 'SKIPPED')]
print(f"Requirement: {req['name']} — Status: {status}")
for e in failed:
print(f" FAILED: policy={e['name']} material={e.get('materialName','-')} status={e.get('status','-')}")
This gives you the list of failing material names (e.g. control-plane-migrations-report).
Step 3: Download the SARIF for Each Failing Material
From the list_pieces_of_evidence result (Call B above), find the item whose name matches the failing material name and whose kind is SARIF. Use its digest field directly — no need to decode attestations.
Call download_evidence_by_digest with:
digest: the digest of the matching SARIF itemdownload_content:true
The SARIF logicalLocations[].fullyQualifiedName field contains the full image reference, e.g.:
ghcr.io/chainloop-dev/chainloop/control-plane-migrations:v1.77.0@sha256:<digest>:/atlas
The binary path (e.g. /atlas, /app) tells you which binary inside the image is vulnerable.
Step 4: Identify the Fix
4a. Atlas / Migration Dockerfile vulnerabilities
Symptom: SARIF location is /atlas, image is control-plane-migrations
Source file: app/controlplane/Dockerfile.migrations
Fix procedure:
- Check the current atlas version in the comment at the top of the Dockerfile (e.g.
# atlas version v1.1.0) - Find the latest available version:
curl -s "https://registry.hub.docker.com/v2/repositories/arigaio/atlas/tags?page_size=20&ordering=last_updated" \ | python3 -c "import json,sys; [print(t['name']) for t in json.load(sys.stdin)['results'] if t['name'][0].isdigit() and '-' not in t['name']]" - Run grype on the current and candidate versions to confirm the CVEs are present then gone:
A clean run has only the header line and no CVE rows.grype arigaio/atlas:<current-version> --only-fixed 2>&1 grype arigaio/atlas:<new-version> --only-fixed 2>&1 - Once a clean version is confirmed, pull it and get its digest:
docker pull arigaio/atlas:<new-version> docker inspect --format='{{index .RepoDigests 0}}' arigaio/atlas:<new-version> - Update
app/controlplane/Dockerfile.migrations:# from: arigaio/atlas:<NEW_VERSION> # docker run arigaio/atlas@sha256:<NEW_DIGEST> version # atlas version v<NEW_VERSION> FROM arigaio/atlas@sha256:<NEW_DIGEST> as base
4b. Go stdlib / Go module vulnerabilities (backend)
Symptom: SARIF location is a Go binary (e.g. /app, /server), package is stdlib or a Go module
Fix options (in order of preference):
Option A — Upgrade Go version (for stdlib CVEs):
Use the upgrading-golang skill to bump the Go version in go.mod and all Dockerfiles.
Option B — Upgrade a specific Go dependency (for third-party modules):
- Identify the affected module from the SARIF
purlsfield (e.g.pkg:golang/github.com/foo/bar@v1.2.3) - Update
go.mod:go get github.com/foo/bar@<fixed-version> go mod tidy - Verify with grype:
grype dir:. --only-fixed 2>&1
Step 5: Verify the Fix with Grype
Always run grype before and after the change to confirm the CVEs are resolved:
# Before — should show the CVE rows
grype <image>:<current-version> --only-fixed 2>&1
# After — should show header only, no CVE rows
grype <image>:<new-version> --only-fixed 2>&1
A clean run has only the column header line and zero data rows.
Step 6: Commit and Create a PR
-
Check which branch you are on — do not create a new branch if one already exists:
git branch --show-current -
Commit with signoff (no co-author):
git add <changed-files> git commit -s -m "fix(<scope>): <short description of the CVE fix>" git push -u origin <current-branch> -
Create the PR with
gh pr create:gh pr create --title "fix(<scope>): <short description>" --body "$(cat <<'EOF' ## Summary - <bullet: what was upgraded and why> - Fixes <CVE-ID> (<Severity>) and <CVE-ID> (<Severity>) in <package> - <brief note on how the fix works, e.g. new version built with Go X.Y.Z> EOF )"
Step 7: Report Results
Summarise the findings and changes in this format:
## Vulnerability Remediation Summary
**Project**: chainloop v<version>
**Requirement**: no-vulnerabilities-high — was: FAIL
### Fixed
| CVE | Severity | Package | Old Version | Fix Applied |
|-----|----------|---------|-------------|-------------|
| CVE-XXXX-XXXXX | Critical | <pkg> | <old> | Upgraded <file> to <new> |
### Files Changed
- `app/controlplane/Dockerfile.migrations` — atlas vX.X.X → vX.X.X
### PR
<GitHub PR URL>
Key Reference Data
| Item | Value |
|---|---|
| Chainloop org | chainloop |
| Project name | chainloop |
| chainloop-best-practices framework ID | 0ceef195-6900-4166-8407-77eb84954ed3 |
| Continuous-scanning workflow ID | c506a425-d307-4a59-9132-659ffd417b57 |
| Migrations Dockerfile | app/controlplane/Dockerfile.migrations |
| Backend go.mod | go.mod (root) |
Important Notes
- Always pin Docker images by SHA256 digest, not tag alone
- For Go stdlib CVEs, upgrading the atlas or golang builder image is usually sufficient — check via grype before touching go.mod
- Run
go mod tidyafter any go.mod change - The compliance-scanning runs daily, so the policy status will update automatically after the fix is merged and a new image is built