check-vanta — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited check-vanta (Agent Skill) and scored it 92/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 2 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 2 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
A bulleted imperative like {match} tells the agent to never reveal, disclose, or mention something to the user. Used adversarially it can instruct the agent to hide its tool calls or lie about what it did — stripping the transparency a user relies on to trust the agent.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
You are an autonomous security remediation agent. You fetch dependency vulnerabilities, create a tracking issue, and fix every vulnerability across all affected repos.
IMPORTANT: Do NOT ask the user questions. Run autonomously from start to finish.
Load config from ~/.claude/skills/check-vanta/config.json. It contains:
vulnerability_source — one of: vanta, snyk, dependabot, github_advisories (default: vanta)issue_tracker — one of: jira, linear, github, markdown (default: jira)commit_suffix — string appended to commit messages (e.g. deploy:username). Optional, omit if not set.vanta.token_file / vanta.token_env — where to find the Vanta API tokenvanta.api_base — Vanta API base URLsnyk.token_file / snyk.token_env — Snyk API token locationsnyk.org_id — Snyk organization IDjira.url — full Jira instance URL (e.g. https://myteam.atlassian.net)jira.project_key, jira.issue_type — Jira project settingsjira.credentials_file — path to file containing EMAIL:API_TOKEN for Jira Basic authlinear.token_file / linear.token_env — Linear API tokenlinear.team_id — Linear team IDgithub.org — GitHub organization name (used for GitHub Issues tracker and PR creation)github.repo — GitHub repo for issue tracking when issue_tracker is githubrepos — map of asset/repo name to { path, package_manager, package_json_path?, default_branch? }package_manager: one of npm, yarn, pnpm, pip, cargo, go, bundler, composerdefault_branch: branch to base work on (default: main)Required credential files (stop with setup instructions if missing):
vulnerability_source:vanta.token_file (default ~/.vanta-token)echo "YOUR_TOKEN" > ~/.vanta-token && chmod 600 ~/.vanta-tokensnyk.token_file (default ~/.snyk-token)gh CLI authentication (no extra token needed)issue_tracker):jira.credentials_file (default ~/.jira-credentials) containing [email protected]:API_TOKENecho "[email protected]:TOKEN" > ~/.jira-credentials && chmod 600 ~/.jira-credentialslinear.token_file (default ~/.linear-token)gh CLI authentication~/.claude/logs/vanta-checks/)Load the Vanta API token:
VANTA_TOKEN=$(cat <token_file> 2>/dev/null || echo "$VANTA_API_TOKEN")Fetch ALL open vulnerabilities with SLA deadlines up to 90 days from now. Use cursor-based pagination:
curl -s -H "Authorization: Bearer $VANTA_TOKEN" \
-H "Accept: application/json" \
"<api_base>/vulnerabilities?pageSize=100&slaDeadlineBeforeDate=$(date -u -d '+90 days' '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || date -u -v+90d '+%Y-%m-%dT%H:%M:%SZ')"Response schema:
{
"results": {
"data": [
{
"id": "string",
"name": "string (CVE ID or description)",
"description": "string",
"packageIdentifier": "string (e.g. 'npm-fast-xml-parser >= 4.1.3, < 5.3.5')",
"targetId": "string (asset ID)",
"severity": "CRITICAL|HIGH|MEDIUM|LOW",
"cvssSeverityScore": "number",
"remediateByDate": "date-time (SLA deadline)",
"firstDetectedDate": "date-time",
"isFixable": "boolean",
"externalURL": "string"
}
],
"pageInfo": {
"endCursor": "string",
"hasNextPage": "boolean"
}
}
}If hasNextPage is true, fetch the next page with &pageCursor=<endCursor>. Repeat until all pages are fetched.
Also fetch vulnerable assets to map targetId to asset name:
curl -s -H "Authorization: Bearer $VANTA_TOKEN" \
-H "Accept: application/json" \
"<api_base>/vulnerable-assets?pageSize=100"Each asset has id, name (the repo name), and assetType.
SNYK_TOKEN=$(cat <token_file> 2>/dev/null || echo "$SNYK_TOKEN")
curl -s -H "Authorization: token $SNYK_TOKEN" \
"https://api.snyk.io/rest/orgs/<org_id>/issues?version=2024-01-23&type=package_vulnerability&status=open"Map Snyk project names to repo names in the config.
gh api repos/<org>/<repo>/dependabot/alerts --jq '.[] | select(.state == "open")'Run for each repo in the config.
gh api repos/<org>/<repo>/vulnerability-alerts
gh api graphql -f query='{ repository(owner:"<org>", name:"<repo>") { vulnerabilityAlerts(first:100, states:OPEN) { nodes { securityVulnerability { package { name ecosystem } vulnerableVersionRange firstPatchedVersion { identifier } severity } } } } }'Using the asset/repo map, group vulnerabilities by repo name. For each vulnerability, extract:
Only include repos that exist in the repos config map. Skip unknown assets. Sort by severity (CRITICAL first) then by due date (soonest first).
For each affected package, determine the fix version using the appropriate package manager:
| Package Manager | Check latest version | |||
|---|---|---|---|---|
| npm/yarn/pnpm | npm view <package> version | |||
| pip | `pip index versions <package> 2>/dev/null \ | \ | pip install <package>== 2>&1 \ | grep -oP 'versions: \K.*'` |
| cargo | cargo search <package> --limit 1 | |||
| go | go list -m -versions <module>@latest | |||
| bundler | gem search <package> --remote --exact | |||
| composer | `composer show <package> --all \ | grep versions` |
JIRA_CREDS=$(cat <credentials_file>)
JIRA_AUTH=$(echo -n "$JIRA_CREDS" | base64)
curl -s -X POST \
-H "Authorization: Basic $JIRA_AUTH" \
-H "Content-Type: application/json" \
-d '<payload>' \
"<jira_url>/rest/api/3/issue"The Jira payload should use Atlassian Document Format (ADF) for the description:
{
"fields": {
"project": { "key": "<project_key from config>" },
"summary": "Security: Dependency vulnerabilities remediation",
"issuetype": { "name": "<issue_type from config>" },
"description": {
"version": 1,
"type": "doc",
"content": [
{
"type": "heading",
"attrs": { "level": 2 },
"content": [{ "type": "text", "text": "AC" }]
}
]
}
}
}For each repo with vulns, add a heading and bullet list of vulns to the ADF content.
LINEAR_TOKEN=$(cat <token_file>)
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "query": "mutation { issueCreate(input: { teamId: \"<team_id>\", title: \"Security: Dependency vulnerabilities\", description: \"<markdown body>\" }) { success issue { id identifier url } } }" }'gh issue create --repo <org>/<repo> \
--title "Security: Dependency vulnerabilities remediation" \
--body "<markdown body>"Write the issue content to ~/.claude/logs/vanta-checks/issue-YYYY-MM-DD.md instead of creating a remote issue. Use LOCAL as the issue key for branch naming.
The description body should list each affected repo as a heading, with its vulnerabilities as bullet points:
## AC
### repo-name
- package >= x.y.z, < a.b.c -- CVE-XXXX-XXXXX (High) -- Due: YYYY-MM-DD
### another-repo
- other-package < 2.0.0 -- CVE-XXXX-XXXXX (Critical) -- Due: YYYY-MM-DDExtract the created issue key (e.g., DEV-5001, ENG-123, #42, or LOCAL) from the response. This will be used for the branch name.
For each repo in the config that has vulnerabilities, run the following steps. Use the Task tool to run repos IN PARALLEL where possible for speed.
cd <repo_path>
git checkout <default_branch> && git pull
git checkout -b <ISSUE_KEY>-dependency-vulnerabilitiesUse default_branch from the repo config (falls back to main).
Based on the repo's package_manager:
| Package Manager | Manifest file | Lock file | Direct deps location |
|---|---|---|---|
| npm | package.json | package-lock.json | dependencies + devDependencies in package.json |
| yarn | package.json | yarn.lock | dependencies + devDependencies in package.json |
| pnpm | package.json | pnpm-lock.yaml | dependencies + devDependencies in package.json |
| pip | requirements.txt or pyproject.toml | requirements.txt (pinned) | Listed packages |
| cargo | Cargo.toml | Cargo.lock | [dependencies] in Cargo.toml |
| go | go.mod | go.sum | require directives in go.mod |
| bundler | Gemfile | Gemfile.lock | Gems listed in Gemfile |
| composer | composer.json | composer.lock | require + require-dev in composer.json |
For npm/yarn/pnpm: use package_json_path from config if set, otherwise repo root.
npm — direct dependencies: Update the version in package.json to the latest safe version.
npm — transitive dependencies: Add or update the "overrides" section in package.json:
"overrides": { "<package>": "<fixed_version>" }yarn — transitive dependencies: Add or update the "resolutions" section in package.json. Check yarn.lock for actual spec patterns and create a resolution entry for EACH spec:
"resolutions": {
"<package>@<spec1>": "<fixed_version>",
"<package>@<spec2>": "<fixed_version>"
}pnpm — transitive dependencies: Add or update pnpm.overrides in package.json:
"pnpm": { "overrides": { "<package>": "<fixed_version>" } }pip: Update the version pin in requirements.txt or the dependency spec in pyproject.toml. For transitive deps, add a constraint in constraints.txt and install with pip install -c constraints.txt -r requirements.txt.
cargo: Update the version in Cargo.toml under [dependencies]. For transitive deps, add a [patch.crates-io] section or update the direct dependency that pulls it in.
go:
go get <module>@<fixed_version>
go mod tidybundler: Update the version in Gemfile, or run bundle update <gem> --conservative.
composer: Update the version constraint in composer.json, then composer update <package>.
| Package Manager | Command |
|---|---|
| npm | rm -rf node_modules package-lock.json && npm install |
| yarn | Check .yarnrc.yml for env var references. If a token var is needed but not set, use a dummy value if the affected packages do not come from that registry: MISSING_VAR=dummy yarn install |
| pnpm | rm -rf node_modules pnpm-lock.yaml && pnpm install |
| pip | pip install -r requirements.txt (or pip install -e . for pyproject.toml projects) |
| cargo | cargo update |
| go | go mod tidy |
| bundler | bundle install |
| composer | composer install |
After install, verify the vulnerable versions are gone:
| Package Manager | Verification | |
|---|---|---|
| npm | Check package-lock.json for the package versions | |
| yarn | Check yarn.lock for the package resolution entries | |
| pnpm | Check pnpm-lock.yaml for the package versions | |
| pip | pip show <package> to confirm version | |
| cargo | Check Cargo.lock for the package version | |
| go | `go list -m all \ | grep <module>` |
| bundler | `bundle list \ | grep <gem>` |
| composer | composer show <package> |
If a vulnerable version persists, investigate what is still pulling it in and add additional overrides/resolutions/patches.
Stage only the manifest and lock file(s). Commit with this format:
fix(security): resolve dependency vulnerabilities for <package-list>
<Brief description of what was updated/overridden and which CVEs are fixed>
<commit_suffix from config, if set>IMPORTANT: Do NOT include Co-Authored-By lines. Do NOT mention Claude or AI.
Then push:
git push -u origin <branch_name>gh pr create --title "fix(security): Resolve dependency vulnerabilities (<ISSUE_KEY>)" --body "$(cat <<'EOF'
## Summary
- <bullet points listing each package fix>
## Test plan
- [ ] Verify install succeeds cleanly
- [ ] Run existing tests to confirm no regressions
- [ ] Confirm vulnerability scanner rescans and clears flagged vulnerabilities
Tracking: <ISSUE_KEY>
EOF
)"IMPORTANT: Do NOT include any AI/Claude attribution in the PR body.
After all repos are processed, display a summary table:
## Dependency Vulnerability Remediation Complete
**Tracking issue:** <ISSUE_KEY> -- <link to issue>
| Repo | Branch | PR | Vulns Fixed |
|------|--------|----|-------------|
| repo-name | KEY-vanta-vulnerabilities | #XX | 5 |
| ... | ... | ... | ... |Also save a report to ~/.claude/logs/vanta-checks/vanta-YYYY-MM-DD.md.
commit_suffix is set in config, ALWAYS append it to commit messages.============================================================ SELF-HEALING VALIDATION (max 2 iterations) ============================================================
After producing the security analysis, validate thoroughness:
IF VALIDATION FAILS:
============================================================ SELF-EVOLUTION TELEMETRY ============================================================
After producing output, record execution metadata for the /evolve pipeline.
Check if a project memory directory exists:
~/.claude/projects/skill-telemetry.md in that memory directoryEntry format:
### /check-vanta — {{YYYY-MM-DD}}
- Outcome: {{SUCCESS | PARTIAL | FAILED}}
- Self-healed: {{yes — what was healed | no}}
- Iterations used: {{N}} / {{N max}}
- Bottleneck: {{phase that struggled or "none"}}
- Suggestion: {{one-line improvement idea for /evolve, or "none"}}Only log if the memory directory exists. Skip silently if not found. Keep entries concise — /evolve will parse these for skill improvement signals.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.