Back to skill

Security audit

Clawhub Publish Security

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent local security scanner, but it can print detected secrets verbatim and gives users an overconfident pre-publish safety signal despite incomplete scanning rules.

Install only if you are comfortable with a local scanner that reads the target skill directory. Do not run it in shared CI logs or on real secrets unless output is redacted, and do not treat a clean result as complete proof that a skill is safe to publish; manually review skipped configuration files and rotate any secret that may have been printed in logs.

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 (3)

T09 · Insecure Skill Coding Practices

Warning
Location
security-scan.py:181
Finding

Detected Secrets Are Printed Verbatim to Terminal and CI Logs

Content
View full analysis
1 else ''})") for issue in type_issues: print(f" - {issue['file']}:{issue['line']}: \"{issue['match']}\"") else: print(f"[OK] {issue_type}: CLEAN (0 found)") ``` ### Technical Analysis The scanner stores the complete text matched by its credential-detection expressions and then prints that value without redaction. Depending on the finding type, `issue['match']` can contain a complete API key, authentication token, password, private key assignment, or other secret. Although the scanner does not transmit findings over a network itself, terminal output is frequently captured by CI/CD systems, build logs, shell-session recording, centralized logging agents, or shared audit artifacts. Consequently, a secret initially confined to a source file can be copied into additional systems with broader access and longer retention periods. The documentation recommends using the scanner in CI/CD, increasing the practical likelihood that its output will be retained. ### Attack Path 1. A scanned project contains an API key, token, password, or secret matching one of the configured expressions. 2. A developer or automated pipeline runs `security-scan.py` as recommended. 3. `scan_file()` stores the complete matched assignment in the `match` field. 4. `print_results()` interpolates the unredacted value into terminal output. 5. The terminal or CI system retains the output in a log. 6. A user with access to those logs, but not necessarily the original source repository or secret-bearing file, obtains the credential. ### Impact As ...[truncated 596 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
security-scan.py:93
Finding

Unanchored Placeholder Exemptions Allow Credential Detection Bypass

Content
View full analysis
bool: """Check if match is a safe placeholder.""" safe_patterns = [ r"", # Placeholders like r"os\.environ\.get", # Environment variable access r"getenv\(", # Environment variable access r"%[A-Z_]+%", # Windows env vars r"\$[A-Z_]+", # Unix env vars r"author.*\(.*\)", # Author attribution (safe) r"https?://", # URLs (safe) r"C:\\[A-Za-z]+\\", # Generic Windows paths (C:\App\) r"~/", # Home directory (safe) r"XXX", # XXX placeholder r"placeholder", # placeholder@placeholder.com r"Users\\name", # Documentation example r"Users\\vilda", # This file's author (documentation) ] for safe_pattern in safe_patterns: if re.search(safe_pattern, match, re.IGNORECASE): return True return False ``` ```python for match in matches: matched_text = match.group() # Skip if it's a placeholder if self.is_placeholder(matched_text): continue ``` ### Technical Analysis The scanner uses unanchored, case-insensitive `re.search()` checks to decide whether an otherwise sensitive match is safe. Broad patterns such as `XXX` and `placeholder` therefore exempt any credential assignment containing those substrings anywhere in the matched text. For example, a value such as the following still matches the token-detection expression but is subsequently suppressed: ```python token = "liveXXXsecretvalue" ``` The problem is amplified because `is_placeholder()` receives the entire regex match, including the assignment name and value, rather than a separately captured and normalized value. Other broad ...[truncated 1599 chars]
Remediation
View remediation
bool: normalized = value.strip().strip("'\"") return re.fullmatch(r"", normalized) is not None ``` Credential patterns should capture the assigned value separately before calling this function. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
security-scan.py:87
Finding

Extension Allowlist Silently Skips Common Secret-Bearing Files

Content
View full analysis
bool: """Check if file type should be scanned.""" safe_extensions = {'.py', '.md', '.json', '.txt', '.sh', '.ps1', '.yaml', '.yml', '.js', '.ts'} return filepath.suffix.lower() in safe_extensions ``` The exclusion is applied when files are scanned: ```python def scan_file(self, filepath: Path): """Scan single file for sensitive data.""" if not self.is_safe_file(filepath): return ``` ### Technical Analysis Despite recursively traversing the target directory, the scanner reads only files whose suffix appears in a narrow allowlist. Common secret-bearing formats are omitted, including: - `.env` and related environment files - `.toml` - `.ini` - `.cfg` - XML configuration files - Extensionless configuration files and scripts - `Dockerfile` and similarly named build files A file skipped by this check produces no warning and is not represented in the final result. If all inspected files are clean, the scanner prints `ALL CHECKS PASSED` and exits with status 0, even when an omitted file contains a plaintext credential. This contradicts the tool's role as a mandatory pre-publication scanner because the successful status does not distinguish a comprehensively clean project from one containing uninspected files. ### Attack Path 1. A credential is placed accidentally or intentionally in an unsupported file such as `.env`, `config.toml`, `settings.ini`, or `Dockerfile`. 2. Recursive traversal discovers the file. 3. `is_safe_file()` returns `False` because the suffix is absent from the allowlist. 4. `scan_file()` returns without reading or reporting the file. 5. No issue is added for the plaintext credential. 6. The scanner reports that all checks passed and exits succ ...[truncated 600 chars]
Remediation
View remediation
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · README.md (reported line 239)May include surrounding context.

md
## 🔗 Related Tools

- **clawhub-smart-updater** - Update skills safely
- **openclaw-safe-audit** - Security audit for OpenClaw
- **edgeone-clawscan** - Tencent security scanner

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `SKILL.md` | 🟡 Medium | Config examples |

Static analysis

No suspicious patterns detected.