Back to skill

Security audit

Proof Agent

Security checks for vulnerabilities and agentic risk

Overview

This skill is a legitimate verification helper, but it handles repository text and URLs in ways that can mislead verifier agents or make unintended network requests.

Review this skill before installing in repositories you do not fully trust. Use it only where verifier agents treat repo metadata as untrusted evidence, and avoid running fact-check.sh on untrusted files unless network egress is sandboxed or restricted to approved public domains.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T01 · Skill Instruction Hijacking

Error
Location
scripts/verify.sh:13
Finding

Repository Metadata Can Inject Instructions into the Verifier Prompt

Content
View full analysis
/dev/null || git diff --name-only --cached 2>/dev/null || echo "(no git changes detected)") # Count FILE_COUNT=$(echo "$FILES" | grep -c '.' || echo 0) # Get diff summary DIFF=$(git diff --stat "$BASE" HEAD 2>/dev/null || echo "(no diff available)") # Get commit messages since base COMMITS=$(git log --oneline "$BASE"..HEAD 2>/dev/null || echo "(no commits)") ``` ```bash # Build the prompt cat <
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/fact-check.sh:24
Finding

Unrestricted URL Validation Permits Server-Side Request Forgery

Content
View full analysis
/dev/null || echo "000") if [[ "$status" =~ ^[23] ]]; then echo -e " ${GREEN}✓${NC} URL $url → $status" ((PASS_COUNT++)) elif [ "$status" = "000" ]; then echo -e " ${YELLOW}?${NC} URL $url → timeout/unreachable" ((WARN_COUNT++)) else echo -e " ${RED}✗${NC} URL $url → $status" ((FAIL_COUNT++)) fi } ``` ```bash # Extract and check URLs URLS=$(grep -oE 'https?://[^ '\''")<>\]]+' "$file" 2>/dev/null | sort -u || true) if [ -n "$URLS" ]; then echo "" echo "URLs found:" while IFS= read -r url; do # Skip localhost and example URLs if echo "$url" | grep -qE 'localhost|127\.0\.0\.1|example\.com|your-'; then continue fi check_url "$url" done <<< "$URLS" fi ``` ### Technical Analysis The script extracts URLs from potentially untrusted files and passes them to `curl`. The textual denylist only checks for a few substrings and does not provide a reliable network security boundary. The filter does not block private IPv4 ranges, IPv6 loopback or private ranges, link-local addresses, cloud metadata endpoints, alternate numeric IP representations, internal DNS names, or public hostnames that resolve to internal addresses. Because `curl` uses `-L`, an initially permitted URL can also redirect to a restricted destination. The script does not validate the resolved address before the request or revalidate each redirect target. Although the response body is discarded, HTTP status and reachability information are printed. Moreover, issuing a GET request may itself trigger side effects on internal services. ### Attack Path 1. An attacker places a URL in a file that wil ...[truncated 1282 chars]
Remediation
View remediation

other

Note
Location
scripts/fact-check.sh:10
Finding

Post-Increment Operations Cause Premature Termination Under errexit

Content
View full analysis
/dev/null || echo "000") if [[ "$status" =~ ^[23] ]]; then echo -e " ${GREEN}✓${NC} URL $url → $status" ((PASS_COUNT++)) elif [ "$status" = "000" ]; then echo -e " ${YELLOW}?${NC} URL $url → timeout/unreachable" ((WARN_COUNT++)) else echo -e " ${RED}✗${NC} URL $url → $status" ((FAIL_COUNT++)) fi } ``` ```bash if [ "$registry_ver" = "$ver" ]; then echo -e " ${GREEN}✓${NC} npm $pkg@$ver exists" ((PASS_COUNT++)) elif [ -z "$registry_ver" ]; then echo -e " ${RED}✗${NC} npm $pkg@$ver not found on registry" ((FAIL_COUNT++)) else echo -e " ${YELLOW}?${NC} npm $pkg@$ver — registry returned $registry_ver" ((WARN_COUNT++)) fi ``` ```bash if [[ "$status" =~ ^[23] ]]; then echo -e " ${GREEN}✓${NC} Action $repo@$ref exists" ((PASS_COUNT++)) else echo -e " ${RED}✗${NC} Action $repo@$ref → $status" ((FAIL_COUNT++)) fi ``` ### Technical Analysis In Bash arithmetic contexts, `((variable++))` returns an exit status based on the expression's value before incrementing. When a counter starts at zero, the first post-increment evaluates to zero and therefore returns status 1. Because the script enables `set -e`, that status can terminate the script immediately. This applies independently to the first successful, failed, or warning result because all three counters are initialized to zero. Consequently, the script may stop after processing its first check and fail to inspect remaining URLs, packages, actions, or files. It may also omit the final summary and documented aggregate exit behavior. ### Attack Path 1. A user invokes `fact-check.sh` with one or more ...[truncated 843 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill claims to provide independent adversarial verification, but the documented behavior relies on local shell scripts and external network lookups without clearly declaring those capabilities or guaranteeing an actual separate verifier process. This mismatch can mislead operators into trusting a stronger security review than is actually performed, while also allowing undeclared outbound requests to external services.

Content

No source excerpt is available for this finding.

Context Leakage

High
Category
Data Exfiltration
Confidence
83% confidence
Finding

The script automatically gathers changed file names, diff statistics, and commit messages and emits them into a verifier prompt. In an agent setting, that can expose internal repository context, sensitive filenames, secrets referenced in diffs, or other metadata to a downstream verifier without minimization or explicit consent. Because this skill is specifically designed to pass context to another agent, the leakage risk is more relevant than in a normal local-only helper script.

Content

Scanner excerpt · scripts/verify.sh (reported line 2)May include surrounding context.

sh
#!/usr/bin/env bash
# verify.sh — Auto-extract context for proof-agent verification
# Usage: ./verify.sh [base-ref]
# Default base-ref: HEAD~1 (last commit)
#

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill explicitly instructs use of shell-based scripts (scripts/verify.sh, scripts/fact-check.sh) but does not declare any permissions or allowed-tools scope. That creates an undeclared capability boundary, making it harder for a host system or reviewer to constrain command execution, filesystem access, and possible subprocess/network behavior.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 17)May include surrounding context.

md
- ANY changed file matches: `*auth*`, `*secret*`, `*permission*`, `Dockerfile`, `*.env*`
- User explicitly asks for verification

Skip verification for:
- Formatting-only changes (whitespace, linting fixes)
- `.gitignore` changes

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
88% confidence
Finding

Verification is disabled by default unless at least three files changed or a simple sensitive-file pattern matches. This creates an unsafe fail-open behavior where small but high-risk changes—such as a one-line auth bypass, dependency pin removal, or prompt injection in a single file—can be skipped entirely. In a security-oriented verification skill, that default materially increases the chance that dangerous changes evade review.

Content

Scanner excerpt · scripts/verify.sh (reported line 34)May include surrounding context.

sh
done

# Determine if verification is needed
SHOULD_VERIFY=false
if [ "$FILE_COUNT" -ge 3 ]; then
  SHOULD_VERIFY=true
fi

Static analysis

No suspicious patterns detected.