Back to skill

Security audit

Agent Marketplace

Security checks for vulnerabilities and agentic risk

Overview

The marketplace skill is coherent, but its installer can save unverified remote or registry-provided code locally, which needs user review before use.

Review this before installing or using it with real registries. Use only trusted HTTPS registries, do not install unsigned or unverified skills through this code, and avoid storing sensitive user identifiers or activity unless the cache directory permissions and retention policy are acceptable.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (3)

T08 · Insecure Dependencies

Warning
Location
src/installer.js:174
Finding
<![CDATA[Untrusted Package Retrieval Without Origin, Integrity, or Size Validation]]><![CDATA[ ## Vulnerability Details **File Location**: `src/installer.js:174-194` **Vulnerability Type**: Arbitrary package source retrieval, server-side request forgery, and unverified supply-chain content **Risk Level**: Medium ### Vulnerable Code ```javascript if (skill.downloadUrl) { return new Promise((resolve, reject) => { const url = skill.downloadUrl; const client = url.startsWith('https:') ? https : http; const req = client.get(url, { timeout: 60000 }, (res) => { if (res.statusCode !== 200) { reject(new Error(`Download failed with status ${res.statusCode}`)); return; } const chunks = []; res.on('data', chunk => chunks.push(chunk)); res.on('end', () => { const data = Buffer.concat(chunks); fs.writeFileSync(targetDir, data); resolve(targetDir); }); }); ``` ### Technical Analysis The installer treats the registry-provided `skill.downloadUrl` as trusted. It selects either the HTTPS or HTTP client based solely on the URL prefix and then requests the destination without validating: - The URL protocol - The destination hostname or resolved IP address - Whether the destination belongs to an approved package host - Whether the destination resolves to loopback, link-local, private-network, or cloud metadata infrastructure - The package's cryptographic digest or publisher signature - The response content type or package format - The maximum response size The response is accumulated completely in memory through `Buffer.concat(chunks)` and written to disk without authenticity verification. Consequently, a malicious or compromised registry can direct the process to internal services or provide a modified package. The lack of a response-size limit also permits memory exhaustion if the remote endpoint sends a very large response. The current repository's `installer.js` is incomplete and is not exported by `src/index.js`. This reduces immediate reachability through ...[truncated 1689 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse package URLs with the standard `URL` class and reject malformed URLs. 2. Permit only `https:` URLs in production. 3. Maintain an explicit allowlist of trusted package distribution hostnames. 4. Resolve the hostname before connecting and reject loopback, private, link-local, multicast, reserved, and cloud metadata address ranges for both IPv4 and IPv6. 5. Revalidate the destination after redirects and either reject redirects or enforce the same policy on every redirect target. 6. Require an immutable SHA-256 or stronger package digest from a signed registry manifest. 7. Verify publisher signatures and package provenance before writing or installing content. 8. Enforce a strict maximum response size while streaming rather than buffering the entire response in memory. 9. Validate the response status, content type, expected package format, and archive structure. 10. Write downloads to a securely created temporary file, verify them, and then atomically move them into place. 11. Add tests covering internal IP addresses, DNS rebinding, redirects, plaintext HTTP, digest mismatches, malformed packages, and oversized responses. ]]>

T08 · Insecure Dependencies

Warning
Location
src/installer.js:216
Finding
<![CDATA[Registry-Provided JavaScript Is Persisted Without Authenticity Verification]]><![CDATA[ ## Vulnerability Details **File Location**: `src/installer.js:216-220` **Vulnerability Type**: Unverified executable content installation **Risk Level**: Medium ### Vulnerable Code ```javascript if (skill.code) { fs.writeFileSync( path.join(targetDir, 'index.js'), skill.code ); } ``` ### Technical Analysis The installer writes `skill.code` directly into `index.js`. Skill metadata can originate from a local registry record or a remote registry response, but the code does not verify a publisher signature, package digest, provenance record, permission manifest, or content policy before persisting executable JavaScript. This repository does not execute the generated `index.js`, so direct remote code execution is not demonstrated within the audited code. However, the file is placed in the skill installation location and is evidently intended to be consumed as installed skill code. A later component that imports or executes that file would run content controlled by the registry. The current `installer.js` file is incomplete and is not exported from `src/index.js`, which limits present reachability. The trust-boundary defect remains security-relevant if installation functionality is completed or connected to the public API. ### Attack Path 1. An attacker publishes a malicious skill, modifies a local registry entry, compromises the configured registry, or intercepts registry traffic where plaintext HTTP is used. 2. The attacker places arbitrary JavaScript in the skill record's `code` property. 3. A user requests installation of the affected skill. 4. The installer writes the attacker-controlled source to `<targetDir>/index.js` without signature or digest verification. 5. A marketplace host, agent runtime, or another downstream component loads the installed skill. 6. The JavaScript executes with the privileges of that downstream Node.js process. ### Impact Assessment The immediate operation grants the attacker control over executable file ...[truncated 687 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not accept inline executable source code directly from ordinary registry metadata. 2. Distribute skills as immutable, versioned packages with cryptographic digests. 3. Require publisher signatures rooted in a trusted key or certificate policy. 4. Verify the package name, version, digest, and publisher identity before installation. 5. Record and display package provenance to the user before approval. 6. Scan package contents for prohibited files and dangerous behavior. 7. Require each skill to declare its filesystem, network, subprocess, and credential-access permissions. 8. Execute installed skills in an isolated process or sandbox with minimal filesystem and network access. 9. Require explicit user confirmation before installing unsigned or newly trusted publishers. 10. Use atomic installation and preserve a verified rollback copy. 11. Add tests proving that unsigned content, invalid signatures, digest mismatches, and unauthorized publisher changes are rejected. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
src/registry.js:70
Finding
<![CDATA[Registry Communication Can Be Downgraded to Plaintext HTTP]]><![CDATA[ ## Vulnerability Details **File Location**: `src/registry.js:12, 70-77` **Vulnerability Type**: Insecure transport configuration for security-sensitive registry metadata **Risk Level**: Low ### Vulnerable Code ```javascript this.registryUrl = options.registry || 'https://clawhub.com/registry'; ``` ```javascript const url = `${this.registryUrl}${endpoint}`; return new Promise((resolve, reject) => { const client = url.startsWith('https:') ? https : http; const req = client.get(url, { timeout: 30000 }, (res) => { let data = ''; ``` ### Technical Analysis The registry manager accepts an arbitrary configured registry URL. If the resulting URL does not begin with `https:`, the code silently uses the plaintext HTTP client. Registry responses influence skill metadata, search results, dependency versions, package URLs, and inline source content. Plaintext HTTP provides neither transport confidentiality nor server authentication, allowing an on-path attacker to inspect and modify responses. The code also constructs the request URL through string concatenation rather than validating the base URL with `URL`. No signed metadata layer compensates for the lack of transport authentication. ### Attack Path 1. A user or deployment configures the marketplace with an `http://` registry URL. 2. The application requests skill or dependency metadata over plaintext HTTP. 3. An attacker with a suitable network position intercepts or modifies the response. 4. The attacker changes skill metadata, dependency versions, `downloadUrl`, or inline `code`. 5. The modified response is parsed and may be cached by the registry manager. 6. Marketplace operations subsequently consume the attacker-controlled metadata, potentially leading to malicious package installation. ### Impact Assessment A network attacker can compromise the integrity and confidentiality of registry traffic when HTTP is configured. The attacker may manipulate: - Search and catalog results - Skil ...[truncated 342 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse `options.registry` with the standard `URL` class during construction. 2. Reject all protocols other than `https:` by default. 3. If HTTP is required for isolated development, require an explicit `allowInsecureHttp` option and emit a prominent warning. 4. Do not permit insecure HTTP mode in production configurations. 5. Authenticate registry metadata using signed manifests in addition to TLS. 6. Validate HTTP status codes before parsing or caching responses. 7. Enforce response-size limits to prevent memory exhaustion. 8. Configure certificate validation normally and avoid adding options that disable TLS verification. 9. Consider certificate or public-key pinning where the operational environment can safely maintain it. 10. Add tests confirming that plaintext HTTP and unsupported URL schemes are rejected by default. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (11)

Self-Modification

High
Category
Rogue Agent
Content
return result;
  }

  // Update skill statistics
  _updateSkillStats(skillName) {
    const skillData = this.ratings[skillName];
    if (!skillData) return;
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.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
Most of the descriptive content and API explanations are written in Chinese, which effectively forces a specific language for users reading the skill documentation. SQP-3 applies because the file does not offer an explicit language choice or justify the locale constraint as region-specific.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This markdown file describes installation management including one-click install, dependency resolution, conflict handling, rollback, and elsewhere documents uninstall/delete capabilities, but it does not warn that these actions can modify the local environment or installed skills. For markdown files, SQP-2 applies when the description omits warnings about behavior that could affect user data or system integrity.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This code performs a network download from a skill-provided URL and writes the downloaded data directly to disk, but there is no visible confirmation prompt, log/print statement, or comment/docstring warning users about this behavior. Because the operation transmits data over the network and modifies local files, it meets the code-file criteria for a missing user warning.

Session Persistence

Medium
Category
Rogue Agent
Content
const dependencies = await this.resolveDependencies(skillName, targetVersion);
    
    // Remove the main skill from dependencies (we'll install it separately)
    const depList = Array.from(dependencies.entries())
      .filter(([key]) => !key.startsWith(`${skillName}@`))
      .map(([, value]) => value);
Confidence
75% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This code writes ratings, reviews, and associated user identifiers to local JSON files, which is a data-affecting file-write operation for a code file. Although the module has brief internal comments, there is no user-facing warning, confirmation, or visible disclosure in this file that submitted data will be persisted on disk under ./.marketplace-cache.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
The code writes registry state to disk and later deletes registry entries and cached files, but there is no confirmation prompt, user-visible message, or explanatory warning in the file for these potentially destructive operations. Users invoking unregister or cache-clearing behavior may not be alerted that local data will be permanently changed or removed.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
This code performs network requests to a remote registry and writes the returned data into local cache files. Although these operations are part of registry functionality, the file provides no confirmation prompt, user-visible logging, or explanatory comment/docstring warning that remote access and local file writes will occur.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The code persists per-user interaction history and preference data to a local JSON file without any visible access controls, retention limits, consent flow, or minimization. Even if this is intended for personalization, storing searched, viewed, installed, and rated activity on disk creates a privacy and data-exposure risk if the host is multi-user, the cache directory is readable by other processes, or the files are later collected in backups/log bundles.

Missing User Warnings

Low
Confidence
80% confidence
Finding
The usage example configures a remote registry URL and installs a skill from it, which implies network access and retrieval of external packages, but the markdown provides no warning about contacting a remote service or trusting third-party package content. Under SQP-2 for markdown, user-facing documentation should disclose behaviors that may affect privacy or system integrity.

Missing User Warnings

Low
Confidence
91% confidence
Finding
The installer writes package.json and optionally index.js into the target directory, but this file creation is not accompanied by any confirmation, logging, or explanatory warning in the code. For a code file, file writes that affect the user's workspace should have some form of disclosure unless clearly communicated elsewhere.

Static analysis

No suspicious patterns detected.