Back to skill

Security audit

Portable Tools

Security checks for vulnerabilities and agentic risk

Overview

This is mostly a portability guide, but it teaches OAuth/keychain debugging in a way that can expose real credential values.

Review before installing. If used, do not paste full tokens, refresh tokens, keychain payloads, passwords, cookies, or raw credential records into chat, logs, screenshots, or tickets. Use redacted values, boolean checks, expiration timestamps, or non-reversible fingerprints instead, and run the checklist only against directories you intentionally choose.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:42
Finding

Credential Disclosure Through Required Before-and-After Proof

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 42-59
Vulnerability Type: Exposure of plaintext sensitive data
Risk Level: High

Vulnerable Code Snippet

markdown
**Require:**
- Concrete BEFORE state (exact values)
- Concrete AFTER state (exact values)
- Proof they're different (side-by-side comparison)

**Example from OAuth refresher:**

BEFORE:

  • Access Token: POp5z1fi...eSN9VAAA
  • Expires: 1769189639000

AFTER:

  • Access Token: 01v0RrFG...eOE9QAA ✅ Different
  • Expires: 1769190268000 ✅ Extended
text

**Action:** Always show data transformation with real values

The same unsafe practice is reinforced at:

  • SKILL.md, lines 193-195:
    markdown
    **Don't say:** "It should work now"  
    **Show:** "Here's the BEFORE token (POp5z...), here's AFTER (01v0R...), they're different"
    
  • README.md, lines 48-50:
    markdown
    2. **How do I prove this works?**
       - Can I show BEFORE/AFTER with real values from different setups?
    
  • pre-publish-checklist.sh, line 104:
    bash
    echo "   (showed BEFORE/AFTER with real values?)"
    

Technical Analysis

The skill instructs users or agents to prove OAuth refresh behavior by displaying exact, real before-and-after values. The surrounding examples explicitly concern access tokens, refresh tokens, and operating-system keychain records.

Revealing a complete secret is unnecessary to prove that credential rotation occurred. A secure implementation should compare secrets internally and expose only non-sensitive evidence, such as expiration timestamps, boolean comparison results, or non-reversible fingerprints. Although the example token strings appear partially abbreviated, the imperative to use “exact values” and “real values” could cause an executing agent or user to disclose complete credentials.

Attack Path

  1. A user or agent loads the skill while debugging an OAuth or keychain workf ...[truncated 1203 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace every requirement to show “exact” or “real” secret values with an explicit prohibition on printing complete credentials.
  2. Compare credentials internally and report only whether they differ:
    bash
    if [[ "$BEFORE_TOKEN" != "$AFTER_TOKEN" ]]; then
        printf '%s\n' "Token changed successfully"
    fi
    
  3. If correlation evidence is required, produce a non-reversible fingerprint without printing the source value:
    bash
    token_fingerprint() {
        printf '%s' "$1" | shasum -a 256 | cut -c1-12
    }
    
  4. Prefer safe proof fields such as expiration timestamps, token identifiers explicitly documented as non-secret, refresh status, and boolean comparison results.
  5. Update README.md and pre-publish-checklist.sh to require redacted evidence.
  6. Add a checklist rule that rejects examples or diagnostics containing plaintext tokens, passwords, API keys, session cookies, or private key material.
  7. Treat existing transcripts or logs produced under this guidance as potentially compromised and rotate any credentials that may have been displayed.

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:354
Finding

Raw Credential-Bearing Data Included in Diagnostic Errors

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 354-363
Vulnerability Type: Sensitive-data exposure through error logging
Risk Level: High

Vulnerable Code Snippet

bash
process_data || true  # Ignore errors

Fix: Fail loudly with context

bash
process_data || error "Failed to process
Data: $DATA
Expected: { ... }
Check: command_to_verify"

Technical Analysis

The recommended error handler interpolates the complete contents of $DATA into an error message. Elsewhere in the same skill, DATA is populated from security find-generic-password and validated as a structure containing an OAuth refresh token. Consequently, applying this generic error pattern to the documented credential workflow can print complete keychain or OAuth records to standard error.

Error channels are frequently captured more broadly than normal application output. They may be stored by CI systems, shell session recorders, centralized logging services, agent tool transcripts, or support bundles. Processing failures are also more likely when data has an unexpected shape, making raw diagnostic dumps both tempting and dangerous.

Attack Path

  1. A script retrieves credential-bearing content into $DATA, such as a JSON object containing an OAuth refresh token.
  2. An attacker supplies malformed input, or an ordinary schema or processing error occurs.
  3. process_data returns a failure status.
  4. The suggested error branch expands $DATA into the diagnostic message.
  5. The complete sensitive record is written to standard error.
  6. A party with access to terminal history, CI logs, centralized logs, agent transcripts, or support output obtains the credential and may replay it.

An attacker able to influence input structure could deliberately trigger this failure path, but no such external-input channel is implemented directly in this repository.

Impact Assessment

The disclosure may inc ...[truncated 509 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove Data: $DATA from the recommended error pattern.
  2. Log only schema-level and operational context that cannot contain secrets:
    bash
    process_data || error "Failed to process credential data
    Expected fields: claudeAiOauth.refreshToken
    Check the record structure with the documented redacted verifier."
    
  3. If diagnostic correlation is necessary, report only a sanitized record identifier, data length, field names, or truncated hash.
  4. Implement a centralized redaction function that masks tokens, passwords, authorization headers, cookies, private keys, and similarly sensitive fields before logging.
  5. Ensure redaction occurs before values are passed to echo, printf, logging functions, exception handlers, tracing facilities, or agent-visible output.
  6. Add automated tests that inject sentinel secrets and verify that neither standard output nor standard error contains them during success and failure paths.
  7. Disable shell tracing around credential operations and avoid commands that could duplicate secrets into process arguments or debug logs.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (10)

Credential Access

High
Category
Privilege Escalation
Confidence
78% confidence
Finding

Showing access-token examples, even truncated, reinforces a practice of comparing raw token values as proof of success. In an OAuth troubleshooting context, that can normalize exposing credential material and lead users to reveal more than necessary.

Content

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

Example from OAuth refresher:

text
BEFORE:
- Access Token: POp5z1fi...eSN9VAAA
- Expires: 1769189639000

AFTER:

Credential Access

High
Category
Privilege Escalation
Confidence
78% confidence
Finding

This second token example continues the pattern of using credential material as a verification artifact. While the sample appears truncated, the surrounding methodology encourages revealing exact before/after values, which increases the chance of real secret exposure during debugging.

Content

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

  • Expires: 1769189639000

AFTER:

  • Access Token: 01v0RrFG...eOE9QAA ✅ Different
  • Expires: 1769190268000 ✅ Extended
text

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill explicitly instructs users to retrieve and report exact values from keychain-related data, which can directly lead to disclosure of credentials or other secrets to an operator, log, or LLM. In this context, asking for exact secret-bearing values is more dangerous because the skill is designed to troubleshoot OAuth/keychain issues, where the inspected data is likely highly sensitive.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

The referenced command focuses on keychain inspection. While listing account metadata is less severe than dumping secret values, it still directs access to a credential store and can expose sensitive account identifiers or facilitate follow-on credential targeting if used carelessly.

Content

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

Example:

bash
# Vague
"Check keychain"

# Specific
"Run: security find-generic-password -l 'Service' | grep 'acct'"

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

This example uses security find-generic-password -w, which outputs the stored secret material directly, and then parses a refresh token from it. Documentation that includes direct secret-extraction commands materially lowers the barrier to credential disclosure or misuse, especially in an agent skill that may be followed verbatim.

Content

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

Original (Broken)

bash
# Assumes single entry, no validation, no fallback
KEYCHAIN_DATA=$(security find-generic-password -s "Service" -w)
REFRESH_TOKEN=$(echo "$KEYCHAIN_DATA" | jq -r '.refreshToken')
# Use token (hope it's valid)

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

The line extracts a refresh token from keychain-derived data, operationalizing access to long-lived credentials. Refresh tokens are highly sensitive because they can often be exchanged for new access tokens, making accidental disclosure particularly damaging.

Content

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

bash
# Assumes single entry, no validation, no fallback
KEYCHAIN_DATA=$(security find-generic-password -s "Service" -w)
REFRESH_TOKEN=$(echo "$KEYCHAIN_DATA" | jq -r '.refreshToken')
# Use token (hope it's valid)

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 · README.md (reported line 112)May include surrounding context.

⚠️ Errors could be more helpful

text

**Success metric:** Someone with a different setup can use your tool without asking you questions.

---
---

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill contains shell-oriented commands and operational guidance, including credential-store queries, but does not declare any tool scope or permissions boundary. That omission increases the chance an agent or user will apply the skill without understanding that it drives shell access to sensitive local resources.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This section normalizes handling access-token examples and credential-retrieval workflows without warning users not to expose secrets in terminals, logs, screenshots, or chat. Even though the examples are instructional, they can encourage unsafe copying, sharing, or storage of sensitive authentication material.

Content

No source excerpt is available for this finding.

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
80% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

Scanner excerpt · pre-publish-checklist.sh (reported line 113)May include surrounding context.

sh
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Review the portable-tools skill for detailed patterns:"
echo "  ~/clawd/skills/portable-tools/SKILL.md"
echo ""

Static analysis

Detected: suspicious.exposed_secret_literal, suspicious.generated_source_template_injection

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
SKILL.md:51

User-controlled placeholder is embedded directly into generated source code.

Critical
Code
suspicious.generated_source_template_injection
Location
SKILL.md:132