Back to skill

Security audit

Towel Protocol

Security checks for vulnerabilities and agentic risk

Overview

The skill is advertised as trust-score lookup, but it includes under-disclosed scripts that create GitHub repositories, push data, store handshake secrets, and mishandle GitHub tokens.

Review before installing. Do not run the bundled shell scripts with an authenticated GitHub CLI session unless you intentionally want a private GitHub repo created and understand that secrets and tokens may be persisted. Treat any generated handshake seeds as compromised if committed or pushed, and avoid using sensitive internal agent identifiers with the API or scripts.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/towel-link.sh:65
Finding

GitHub Access Token Persisted in Repository Configuration

Content
View full analysis
/dev/null) if [ -n "$TOKEN" ]; then git remote set-url origin "https://x-access-token:${TOKEN}@github.com/$ORG/$REPO_NAME.git" fi ``` ### Technical Analysis The script retrieves the active GitHub authentication token with `gh auth token` and embeds it directly into the repository's remote URL. Git stores this URL in `.git/config`, causing the credential to persist in plaintext after the script terminates. The token-bearing URL is also supplied as an argument to `git remote set-url`. Depending on operating-system process visibility and timing, another local process or user may be able to observe the token in the process argument list. Suppressing standard error does not protect the credential. Any user, process, backup system, diagnostic tool, or automation service capable of reading the repository configuration can recover it. ### Attack Path 1. A user with an authenticated GitHub CLI session invokes `towel-link.sh`. 2. The script obtains the user's active token through `gh auth token`. 3. It embeds the token in the `origin` remote URL. 4. Git writes the URL to `.git/config`. 5. An attacker, local process, backup operator, or later automation task reads the repository configuration or captures the command arguments. 6. The attacker extracts and reuses the token against GitHub. 7. The attacker gains whichever repository or organization privileges are granted to that token until it is revoked or expires. ### Impact Assessment Successful exploitation exposes the invoking user's GitHub credential. The resulting scope depends on the token's permissions and may include: - Reading private repositories - Creating, changing, or deleting repository content - Pushing malicious commits - Accessing organization resources ...[truncated 197 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/towel-link.sh:5
Finding

Path Traversal Through Unvalidated Agent Identifiers

Content
View full analysis
}" THEIR_ID="${2:?Missing their-agent-id}" ORG="${3:?Missing github-org}" REPO_NAME="${MY_ID}--${THEIR_ID}-towel" # Create directory structure mkdir -p "$MY_ID"/{messages,handshakes} mkdir -p "$THEIR_ID"/{messages,handshakes} mkdir -p shared # Add .gitkeep files for d in "$MY_ID"/messages "$MY_ID"/handshakes "$THEIR_ID"/messages "$THEIR_ID"/handshakes shared; do touch "$d/.gitkeep" done ``` From `scripts/towel-shake.sh`: ```bash ACTION="${1:?Usage: towel-shake.sh [response]}" AGENT_ID="$2" RESPONSE="$3" # Find the TOWEL repo (assumes we're in it or it's in a known location) REPO_DIR="${TOWEL_REPO_DIR:-.}" case "$ACTION" in init) # Generate initial handshake seed SEED=$(openssl rand -hex 32 2>/dev/null || head -c 64 /dev/urandom | xxd -p | tr -d '\n') HANDSHAKE_FILE="$REPO_DIR/$AGENT_ID/handshakes/seed-$(date -u +%Y%m%d).json" cat > "$HANDSHAKE_FILE" << EOF ``` The challenge action also constructs a filename directly from the identifier: ```bash echo "$NONCE|$HOUR" > "$REPO_DIR/.last_challenge_$AGENT_ID" ``` ### Technical Analysis The scripts use caller-controlled agent identifiers directly as filesystem path components. Quoting protects against shell word splitting and wildcard expansion, but it does not prevent path traversal. An identifier containing `/`, `../`, or an absolute-path-like construction can cause normalized paths to leave the intended repository directory. In `towel-link.sh`, crafted identifiers affect `mkdir` and `touch`, permitting directory and file creation outside the newly cloned repository. In `towel-shake.sh`, th ...[truncated 1629 chars]
Remediation
View remediation
&2 exit 1 ;; esac } ``` - Explicitly reject `/`, `\`, `..`, control characters, whitespace, and leading hyphens. - Apply a reasonable maximum length. - Resolve the repository and destination paths canonically with `realpath` or equivalent. - Verify that every resolved destination begins with the canonical repository path followed by a path separator. - Create files using restrictive permissions and fail if the expected parent directory is missing. - Avoid deriving sensitive filenames directly from external identifiers; use an internal identifier mapping where possible. - Add tests covering relative traversal, absolute paths, symbolic links, control characters, and malformed identifiers. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/towel-shake.sh:17
Finding

Authentication Seeds Committed to a Shared Remote Repository

Content
View full analysis
/dev/null || head -c 64 /dev/urandom | xxd -p | tr -d '\n') HANDSHAKE_FILE="$REPO_DIR/$AGENT_ID/handshakes/seed-$(date -u +%Y%m%d).json" cat > "$HANDSHAKE_FILE" << EOF { "agent": "$AGENT_ID", "created": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", "seed": "$SEED", "rotation": "daily", "note": "This seed is used to compute handshake responses. Never share outside this repo." } EOF cd "$REPO_DIR" && git add -A && git commit -m "[$AGENT_ID] handshake seed initialized" --quiet ``` The exposed seed is subsequently used to calculate authentication responses: ```bash RESPONSE_HASH=$(echo -n "${NONCE}${MY_SEED}${CONTEXT_HASH}${HOUR}" | shasum -a 256 | cut -d' ' -f1) ``` Verification uses the same shared seed: ```bash EXPECTED=$(echo -n "${NONCE}${THEIR_SEED}${CONTEXT_HASH}${HOUR}" | shasum -a 256 | cut -d' ' -f1) ``` ### Technical Analysis The script stores authentication seeds in plaintext JSON files and then executes `git add -A`, which stages the seed for inclusion in Git history. The associated repository is designed to be shared between agents and pushed to GitHub by `towel-link.sh`. Anyone with repository read access can retrieve both agents' seeds and calculate valid responses. The construction is an unkeyed SHA-256 digest over concatenated values; it does not provide asymmetric proof of identity. Possession of the repository is effectively possession of every authentication credential used by the protocol. Deleting a seed from the current working tree does not remove it from previous Git commits. The credential can remain recoverable from repository history, clones, forks, caches, and backups. ### Attack Path 1. An agent initializes its handshake identity. 2. The script writes its secret see ...[truncated 1359 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/towel-link.sh:17
Finding

Undocumented GitHub Repository Creation and Authenticated Data Upload

Content
View full analysis
/dev/null ``` ```bash git commit -m "[$MY_ID] TOWEL link established with $THEIR_ID" # Set up remote with auth TOKEN=$(gh auth token 2>/dev/null) if [ -n "$TOKEN" ]; then git remote set-url origin "https://x-access-token:${TOKEN}@github.com/$ORG/$REPO_NAME.git" fi git push --set-upstream origin main 2>/dev/null ``` ### Technical Analysis `SKILL.md` primarily describes public reputation lookup endpoints and authenticated credential import against `towel.metaspn.network`. It does not document that bundled tooling will create a private GitHub repository, clone it, commit local content, extract the current GitHub credential, alter the Git remote, and upload data. These operations materially exceed a read-only reputation check and exercise existing GitHub repository-creation and write privileges. The script does not present an explicit confirmation prompt immediately before repository creation or upload, nor does it verify that the selected organization and repository are approved destinations. Although the repository is requested as private, private visibility does not eliminate the risk of unauthorized or unexpected data transfer. Organization administrators, installed applications, automation, or collaborators may have access. ### Attack Path 1. An operator installs the skill based on documentation describing trust-score and profile operations. 2. The operator invokes the bundled link utility while authenticated through GitHub CLI. 3. The script exercises the operator's existing GitHub privileges to create a repository in the supplied organization. 4. It generates and commits ...[truncated 967 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 Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared purpose emphasizes trust verification, reputation lookup, credential import, and displaying trust tiers. The supplied script does none of those things. Instead, its primary function is to create and initialize a new TOWEL link repository between two agent IDs using the GitHub CLI and git. This is a materially different purpose: provisioning communication/trust infrastructure rather than evaluating trust. The description also explicitly excludes self-registration, but the script establishes a new bilateral channel and tells the user to run a handshake-init command next, which is much closer to onboarding/setup than passive observation or verification. Resource access is also undeclared in practice: it uses GitHub account auth, creates private repos, and pushes data remotely. These are significant undeclared capabilities, so this is a clear mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The code does not perform reputation or trust-score retrieval, aggregation, or display. Instead, its core function is challenge-response identity verification using locally stored handshake seeds and git state. It includes an init flow that creates seed material for an agent, which resembles self-initialization/self-registration behavior, conflicting with the description's statement that the tool is not for self-registration. While identity verification could be adjacent to trust assessment, the implemented behavior is materially different from verifying protocol-based reputation/trust scores across platforms.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
98% confidence
Finding

AGENT_ID is fully attacker-controlled and is interpolated into a filesystem path used by rm. An attacker can supply path traversal sequences such as '../../...' to cause deletion of arbitrary files relative to REPO_DIR when verification succeeds, which is especially risky because the script performs file operations in a trust-oriented workflow where inputs may come from external agents.

Content

Scanner excerpt · scripts/towel-shake.sh (reported line 85)May include surrounding context.

sh
if [ "$THEIR_RESPONSE" = "$EXPECTED" ]; then
      echo "✅ VERIFIED: $AGENT_ID identity confirmed"
      # Update trust score
      rm -f "$REPO_DIR/.last_challenge_$AGENT_ID"
    else
      echo "❌ FAILED: Response does not match expected handshake"
      echo "   This may indicate impersonation or a compromised channel"

External Transmission

Medium
Category
Data Exfiltration
Confidence
73% confidence
Finding

The skill directs agents to send agent identifiers and profile lookup values to an external third-party service. In a trust-evaluation workflow, that can leak metadata about which agents a user or system is interacting with, and if callers substitute sensitive internal identifiers into {agentId} or {name}, those values are transmitted off-platform without any mention of minimization, consent, or privacy controls.

Content

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

bash
# Quick trust check — lightweight, designed for agent-to-agent calls
curl https://towel.metaspn.network/api/v1/verify/{agentId}

# Returns: { verified, tier, trust_score, name }

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script performs repository creation, initialization, and trust-channel bootstrapping, which materially exceeds the stated skill scope of verifying trust scores and reputation. This matters because it grants the skill a write/provisioning capability that can create durable infrastructure and side channels on the user's GitHub account, increasing the blast radius if invoked unexpectedly or by an untrusted workflow.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% 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 · scripts/towel-link.sh (reported line 48)May include surrounding context.

sh
- $(date -u +%H:%M) Link established by $MY_ID
- Awaiting $THEIR_ID initial handshake

## Trust Score: 0.0 (no verifications yet)
EOF

# Add protocol reference

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script automatically retrieves the GitHub auth token and uses it to reconfigure the remote and push to GitHub, introducing credentialed external side effects not clearly necessary for passive trust verification. In the context of an agent skill, this is dangerous because a user may expect read-only reputation lookup, while the script can silently create and publish resources using the caller's GitHub authority.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

Embedding an authentication token directly into the Git remote URL is a credential-handling anti-pattern because the token may be exposed through shell history, git configuration, process inspection, debugging output, or accidental repo/log disclosure. Within an agent skill, this is especially risky because the skill may run non-interactively and users may not realize their GitHub credential is being inserted into persisted configuration.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes a skill for verifying agent trust scores and reputation via Towel Protocol, including reputation lookup, credential import, and trust-tier display. This script instead implements a custom handshake system that generates private seeds, issues challenges, computes responses, and verifies identity proofs, which is a materially different capability from querying or presenting reputation data.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The manifest explicitly says the skill is not for self-registration and that agents are observed rather than self-admitted. The init action creates local identity-related seed material for a specified agent and commits it into the repository, which is a form of self-provisioning/bootstrap capability not reflected in the stated scope.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
72% confidence
Finding

The script documentation presents the operation as creating a new trust link between agent identities, which conflicts with the manifest's constraint that the system is not for self-registration. Although phrased as a channel rather than direct admission, the comments describe a bootstrap flow inconsistent with the stated product boundary.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
99% confidence
Finding

The inline comment # Update trust score claims a trust/reputation side effect that does not occur. The actual code only removes the stored challenge file after successful verification, so the documentation overstates behavior and could mislead users about trust-state changes.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.