DEV Community

Cover image for What We Learned Scanning 2,354 ClawHub Skills That Every Skill Author Should Know
George Psistakis for Trent AI

Posted on

What We Learned Scanning 2,354 ClawHub Skills That Every Skill Author Should Know

By Julien Brouchier, MTS @ Trent AI


We ran a behavioral security analysis on 2,354 of the most popular skills on ClawHub. The results: 86% had security issues. But here's the thing: the overwhelming majority weren't malicious. They were built by developers who shipped good tools with preventable gaps.

The same six patterns showed up across the corpus with remarkable consistency. If you publish skills on ClawHub, or plan to, this is what to look for and how to fix it.

Pattern 1: Plaintext Credentials

The most common finding. API keys and tokens stored directly in configuration files, scripts, or SKILL.md.

What we saw

Skills that hardcode API keys in the main script or store them in a config file committed alongside the code. Anyone who reads the source has the key. The thinking is usually some version of: "I'll drop my key in here for testing. I'll swap it out before I publish." Then the publish step happens and the key ships.

Why it matters more for OpenClaw

In a traditional package, a leaked API key is bad. In OpenClaw, the agent actively uses that key. An attacker who compromises the skill has the key and an autonomous agent willing to use it.

The fix

# Instead of this:
API_KEY = "sk-abc123..."

# Do this:
import os
API_KEY = os.environ.get("MY_SERVICE_API_KEY")
if not API_KEY:
    raise ValueError("MY_SERVICE_API_KEY not set")
Enter fullscreen mode Exit fullscreen mode

Document in your SKILL.md that users need to set the environment variable. Never store credentials in any file that ships with the skill.

Pattern 2: Un-scoped API Access

Skills that request broad permissions when they only need a narrow slice.

What we saw

A skill that sends emails requesting full Gmail access instead of just gmail.send. A calendar tool requesting read/write to all calendars when it only needs one. Skills that request filesystem access to / when they only need ./data/.

Why it matters more for OpenClaw

Agents use the permissions they're given. If your skill requests broad access "just in case", you've expanded the blast radius of every vulnerability in your code. A prompt injection attack against a skill with full filesystem access is a completely different incident than one against a skill scoped to a single directory.

The fix

Request the minimum permissions your skill actually needs. If you need to read one file, request access to that file. Not the directory, not the filesystem. Audit your permission requests and ask: "If an attacker controlled the input to this skill, what could they reach?"

Pattern 3: Missing Input Validation

No sanitization of external or user-provided data. Injection vectors left wide open.

What we saw

File paths accepted without validation, meaning a prompt injection could point the skill at ~/.ssh/id_rsa or ~/.aws/credentials. URLs passed directly to HTTP libraries without checking the scheme or domain. User input concatenated into shell commands.

Why it matters more for OpenClaw

Traditional software gets input from users through forms and APIs. OpenClaw skills get input from agents, and agents can be manipulated through prompt injection. The input your skill receives isn't always what the user intended. If you don't validate it, you're trusting the agent's entire conversation context.

The web learned this the hard way in the late 1990s and early 2000s, when SQL injection and XSS taught a generation of developers that all input is untrusted, including input that looks like it came from your own UI. Agentic skills are at the same point right now. The input looks like it came from your user; in practice it came from a model that read whatever was in front of it.

The fix

import os

ALLOWED_DIR = os.path.abspath("./workspace")

def safe_read(filepath):
    resolved = os.path.abspath(filepath)
    if not resolved.startswith(ALLOWED_DIR):
        raise ValueError(f"Path {filepath} outside allowed directory")
    return open(resolved).read()
Enter fullscreen mode Exit fullscreen mode

Validate every input. Allowlist over blocklist. Treat all input as untrusted, regardless of source.

Pattern 4: Unverified External Endpoints

Blind trust in third-party APIs and services.

What we saw

Skills that POST data to external endpoints without verifying the response. Skills that follow redirects without checking the destination. Skills that download and execute code from URLs embedded in configuration.

Why it matters more for OpenClaw

An agent doesn't question whether a URL is trustworthy. It follows instructions. If your skill sends data to an external API, and that API is compromised or spoofed, the agent will dutifully send whatever data it has access to. There's no human in the loop squinting at a suspicious redirect.

The fix

Pin the URLs your skill communicates with and verify TLS certificates. Check response status codes and content types before processing. Never follow redirects blindly. If your skill downloads anything, verify a checksum.

Pattern 5: Missing Sandboxing

No isolation between the skill and the host environment.

What we saw

Skills that run with full host access. Skills that share the agent's environment variables (including credentials for other services). Skills that can read and write to any directory the agent process can reach.

Why it matters more for OpenClaw

OpenClaw agents often have access to multiple tools and services. A skill without sandboxing boundaries can reach everything the agent can reach, not just the resources relevant to the skill's stated function. One compromised skill means every connected service is exposed.

The fix

Run skills in the most restrictive environment possible. If OpenClaw supports permission scoping for your use case, use it. Avoid sharing environment variables between skills. Each skill should only see the credentials it needs. Document what your skill accesses so users can make informed decisions.

Pattern 6: Auto-push Without Approval

Skills that write to git, send messages, or make API calls with no user confirmation step.

What we saw

Skills that commit and push to repositories automatically. Skills that send Slack messages, emails, or webhooks without asking. Skills that create or modify cloud resources without a confirmation prompt.

Why it matters more for OpenClaw

This is the pattern that turns a vulnerability into an incident. A skill with unvalidated input AND auto-push can be manipulated into committing malicious code, sending phishing messages, or modifying infrastructure, all without the user seeing it happen. The agent executes, the skill pushes, and nobody reviews the action.

The fix

Add a confirmation step for any destructive or externally-visible operation. At minimum, log what the skill is about to do and wait for explicit user approval. For git operations: stage the changes and present them before pushing. For API calls: show the payload before sending.

The Pattern Behind the Patterns

These six issues aren't random. They share a root cause: the OpenClaw ecosystem makes it easy to skip these controls and provides no feedback when you do.

There's no pre-publish check that flags plaintext credentials. No template that starts you off with input validation. No required permissions declaration in the skill spec. Developers build skills the way the ecosystem teaches them, and the ecosystem doesn't teach security.

It's also not obvious where the fix should live. Should it sit in the skill spec, in ClawHub's publish flow, in the host runtime, or in the LLM itself? Web security ran into the same question twenty years ago about input validation: client, business logic, framework, or language. It eventually got answered in layers, not in one place. Agentic skills are still at the question stage.

The 226 benign packages in our scan aren't benign because their developers are better (this is the pattern I keep coming back to). They're benign because their architecture mitigates risk: scoped permissions, validated inputs, explicit user confirmation. The code quality is often similar across all three categories. The architecture is what separates them.

What Separates Vulnerable From Malicious

We also found 103 genuinely malicious packages (4.4%). The diagnostic signal that separates them from vulnerable packages is not the number of findings. It's the density of CRITICAL findings:

Category Avg. findings CRITICAL per package Pattern
Malicious (103) 9-10 4-6 Credential harvesting, data exfiltration, prompt injection
Vulnerable (2,025) 4-6 0-1 Missing validation, plaintext creds, broad permissions
Benign (226) 0-2 Rare Architecture mitigates residual risk

A package with six CRITICAL findings about credential harvesting and data exfiltration is fundamentally different from a package with five HIGH findings about missing input validation, even though both "have security issues."

If you're auditing skills manually, CRITICAL density is the fastest signal to check.

The Checklist

Before you publish your next skill to ClawHub:

  • [ ] All credentials in environment variables, none in code or config files
  • [ ] Permissions scoped to the minimum your skill needs
  • [ ] All file paths validated against an allowed directory
  • [ ] All external URLs pinned and verified
  • [ ] All user/agent input treated as untrusted and sanitized
  • [ ] Destructive operations require explicit user confirmation
  • [ ] Your SKILL.md documents what the skill accesses and why

None of this is hard. The ecosystem just doesn't make it the default yet. Until it does, the responsibility sits with you, the author.


Full research (all findings, attack taxonomy, and confusion matrix): Distinguishing Malicious From Vulnerable: A Security Analysis of 2,354 ClawHub Skills

Methodology deep-dive (Part 1): How We Analyzed 2,354 ClawHub Skills for Security

The analysis was conducted using trentclaw, a security assessment skill for OpenClaw built by Trent AI (our team).

Top comments (0)