Back to skill

Security audit

Virtuals Protocol ACP

Security checks for vulnerabilities and agentic risk

Overview

The ACP commerce skill is broadly coherent, but it needs Review because crafted login or marketplace data could lead to local code execution and exposed account credentials.

Install only if you trust the Virtuals endpoints and are comfortable with an agent-commerce tool that stores credentials locally, can launch tokens and create paid jobs, and can run a background seller process. Before using it for real funds or public listings, fix the unsafe browser-opening code, add strict offering/resource name validation and path containment, update reported vulnerable dependencies, protect config.json, and require explicit human approval for token launch, paid jobs, and seller runtime start.

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

Error
Location
src/lib/open.ts:5
Finding

Shell Command Injection Through Server-Provided Authentication URL

Content
View full analysis
{ const { data } = await apiClient().get<{ data: AuthUrlResponse }>( "/api/auth/lite/auth-url" ); return data.data; } ``` ```ts // src/lib/auth.ts:170-172 output.log(` Opening browser...`); openUrl(authUrl); output.log(` Login link: ${authUrl}\n`); ``` ```ts // src/lib/open.ts:5-20 import { exec } from "child_process"; export function openUrl(url: string): void { const platform = process.platform; let cmd: string; if (platform === "darwin") { cmd = `open "${url}"`; } else if (platform === "win32") { cmd = `start "" "${url}"`; } else { // Linux / others cmd = `xdg-open "${url}"`; } exec(cmd, (err) => { if (err) { // Silently fail — the URL is always printed as fallback } }); } ``` ### Technical Analysis The authentication URL returned by `https://acpx.virtuals.io/api/auth/lite/auth-url` is passed directly to `openUrl()`. That function embeds the value into a command string and invokes it through `child_process.exec()`, which executes the string using a system shell. Surrounding the URL with double quotes does not make this safe. On Unix-like systems, shell substitutions such as `$(...)` and backticks are still evaluated inside double quotes. Other platforms have their own shell metacharacters and quoting behavior. The expected authentication request is consistent with the Skill's declared functionality. However, opening the returned URL through a shell exceeds the minimum privilege required: launching a browser only requires passing the URL as a process argument, not granting it shell interpretation. ### Attack Path 1. An attacker compromises, impers ...[truncated 1096 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/seller/runtime/offerings.ts:32
Finding

Remote Offering Name Enables Path Traversal and Dynamic Module Loading

Content
View full analysis
m.nextPhase === AcpJobPhase.NEGOTIATION ); if (negotiationMemo) { return JSON.parse(negotiationMemo.content).name; } } catch { return undefined; } } ``` ```ts // src/seller/runtime/seller.ts:115-127 const offeringName = resolveOfferingName(data); const requirements = resolveServiceRequirements(data); if (!offeringName) { await acceptOrRejectJob(jobId, { accept: false, reason: "Invalid offering name", }); return; } try { const { config, handlers } = await loadOffering(offeringName); ``` ```ts // src/seller/runtime/seller.ts:187-196 const offeringName = resolveOfferingName(data); const requirements = resolveServiceRequirements(data); if (offeringName) { try { const { handlers } = await loadOffering(offeringName); console.log( `[seller] Executing offering "${offeringName}" for job ${jobId} (TRANSACTION phase)...` ); const result: ExecuteJobResult = await handlers.executeJob( requirements ); ``` ```ts // src/seller/runtime/offerings.ts:32-57 export async function loadOffering( offeringName: string ): Promise { const offeringsRoot = path.resolve( __dirname, "..", "offerings", offeringName ); // offering.json const configPath = path.join(offeringsRoot, "offering.json"); if (!fs.existsSync(configPath)) { throw new Error(`offering.json not found: ${configPath}`); } const config: OfferingConfig = JSON.parse( fs.readFileSync(configPat ...[truncated 3034 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/commands/sell.ts:56
Finding

Offering and Resource Scaffold Names Permit Filesystem Path Traversal

Content
View full analysis
{ if (!offeringName) { output.fatal("Usage: acp sell init "); } const dir = resolveOfferingDir(offeringName); if (fs.existsSync(dir)) { output.fatal(`Offering directory already exists: ${dir}`); } fs.mkdirSync(dir, { recursive: true }); const offeringJson: Record = { name: offeringName, description: "", jobFee: null, jobFeeType: null, requiredFunds: null, requirement: {}, }; fs.writeFileSync( path.join(dir, "offering.json"), JSON.stringify(offeringJson, null, 2) + "\n" ); const handlersTemplate = `import type { ExecuteJobResult, ValidationResult } from "../../runtime/offeringTypes.js"; // Required: implement your service logic here export async function executeJob(request: any): Promise { // TODO: Implement your service return { deliverable: "TODO: Return your result" }; } // Optional: validate incoming requests export function validateRequirements(request: any): ValidationResult { // Return { valid: true } to accept, or { valid: false, reason: "explanation" } to reject return { valid: true }; } // Optional: provide custom payment request message export function requestPayment(request: any): string { // Return a custom message/reason for the payment request return "Request accepted"; } `; fs.writeFileSync(path.join(dir, "handlers.ts"), handlersTemplate); ``` ```t ...[truncated 3060 chars]
Remediation
View remediation
Vulnerability Patterns
  • 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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (52)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description focuses on ACP commerce and marketplace functionality: job creation, agent-to-agent transactions, marketplace discovery/usage, token launch, and service offering registration. This code does none of those things. Instead, it provides local/remote agent management commands (list, switchAgent, create) with authentication, config persistence, API key regeneration, and seller-process shutdown safeguards. While stopping a seller runtime is tangentially related to agent operations, the chunk’s primary behavior is administrative account switching/creation, not ACP marketplace commerce. Therefore the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

This code chunk does not implement the declared commerce-oriented capabilities such as discovering marketplace agents, creating jobs, transacting with other agents, launching a token, or registering service offerings. Instead, its primary purpose is reading and editing the agent's profile information. That is a materially different function from the declared description, so this chunk is a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
87% confidence
Finding

The description claims a broad ACP integration covering marketplace discovery/usage, job creation with other agents, token launching, and service registration. This code chunk only covers the 'sell/register offerings and resources' portion. It scaffolds local offering/resource files, validates configuration and handler exports, registers or deletes offerings/resources through ACP APIs, and lists/inspects seller offerings. There is no implementation of agent discovery, purchasing/using external agents, job creation for transacting with other agents, or token launch/fundraising features. Because major declared capabilities are absent and the actual purpose is materially narrower, this is a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a broad ACP commerce skill covering marketplace discovery, agent-to-agent job creation/transactions, token launching, and service-offering registration. The supplied code does not perform those functions. Instead, it provides CLI commands to start/stop/status/log a local seller runtime daemon, write/read logs, and do a limited preflight check via getMyAgentInfo to warn about missing offerings or local files. While this may support the selling/offering aspect of ACP indirectly, the actual code chunk’s primary purpose is operational runtime management, not the broader commerce capabilities claimed in the description. Therefore the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents a broad ACP marketplace/commerce skill focused on creating jobs, interacting with other agents, fundraising via agent tokens, and registering services. The supplied code chunk instead performs a much narrower and different function: wallet inspection. It queries local agent wallet info and an ACP wallet-balances API, then formats and outputs balances. This is not just a supporting detail for the declared capabilities; it is a distinct wallet utility and none of the headline behaviors in the description are implemented in this chunk. Therefore the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The supplied code chunk is narrowly focused on CRUD-style API calls for ACP job offerings and resources. That partially aligns with the description’s claim about registering service offerings to sell capabilities. However, the declared purpose substantially overstates the implemented behavior by claiming discovery and use of marketplace agents, creation of jobs and transactions with specialized agents, and launching an agent token for fundraising/revenue. None of those capabilities appear in this code. There are no extra undeclared sensitive actions, but there is a material description-to-behavior mismatch because the primary declared scope is much broader than the actual implementation shown.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

The code does relate to ACP/agent infrastructure, but it does not implement the marketplace-facing capabilities emphasized in the description, such as discovering other agents, transacting with specialized agents, launching an agent token, or registering/selling service offerings. Instead, this chunk is focused on auth/session handling and CRUD-style management of the authenticated user's agents and API keys. Those are materially different primary behaviors from the declared description, and include undeclared credential handling capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

This code does not implement the declared ACP marketplace functionality such as discovering agents, creating jobs, transacting with other agents, launching agent tokens, or registering service offerings. Instead, it provides supporting local config and process-management utilities: file I/O for config.json, API key loading, PID persistence/checking, agent activation state, and price formatting. While some of this could support a broader ACP tool, the chunk’s actual behavior is materially different from the declared purpose and includes undeclared local file and process access capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose describes ACP marketplace and agent-commerce features, but the supplied code is only a generic browser-opening helper. Its primary behavior is unrelated to creating jobs, transacting with agents, launching tokens, or registering services. This is a clear description-to-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description describes a commerce/protocol integration skill with external agent marketplace and transactional capabilities. The supplied code chunk does not implement any ACP networking, marketplace discovery, job creation, token launch, registration, or external service interaction. Instead, it is a local output-formatting helper module for CLI display and JSON emission. This is a materially different primary purpose, so the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
Run from the **repo root** (where `package.json` lives). For machine-readable output, always append `--json`. The CLI prints JSON to stdout in `--json` mode. Yo

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
Run from the **repo root** (where `package.json` lives). For machine-readable output, always append `--json`. The CLI prints JSON to stdout in `--json` mode. Yo

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- **Repo root** — `SKILL.md`, `package.json`, `config.json` (do not commit). Run all commands from here.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- **bin/acp.ts** — Unified CLI entry point. Invoke with `acp <command> [subcommand] [args] --json`.

Known Vulnerable Dependency: axios==1.13.4 — 16 advisory(ies): CVE-2026-44494 (axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co); CVE-2026-44495 (axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut); CVE-2025-62718 (Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF) +13 more

High
Category
Supply Chain
Confidence
92% confidence
Finding

The lockfile pins axios 1.13.4, and the reported advisories include SSRF/proxy-bypass and prototype-pollution-related request handling issues. In this skill’s context—discovering and transacting with external agents over the network—HTTP client flaws are particularly relevant because attacker-controlled endpoints, redirects, or proxy settings could influence outbound requests and expose credentials or enable unintended internal access.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: form-data==4.0.5 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
82% confidence
Finding

form-data 4.0.5 is reported as vulnerable to CRLF injection through unescaped multipart field names or filenames. If this skill ever builds multipart requests from agent-supplied or user-supplied metadata, an attacker may be able to alter request structure, inject unintended parts or headers, and potentially smuggle data to downstream services.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: socket.io-parser==4.2.5 — 2 advisory(ies): CVE-2026-69185 (Socket.IO: Zero-attachment Memory Exhaustion); CVE-2026-33151 (socket.io allows an unbounded number of binary attachments)

High
Category
Supply Chain
Confidence
88% confidence
Finding

socket.io-parser 4.2.5 is flagged for unbounded or zero-attachment parsing behavior that can lead to memory exhaustion. Because this skill uses socket.io-client to interact with external services, a malicious server or intermediary could send crafted frames that consume excessive memory and crash or degrade the agent process.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ws==8.18.3 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
87% confidence
Finding

ws 8.18.3 is reported for memory disclosure and memory-exhaustion denial-of-service issues. In a protocol skill that maintains websocket-style communications with remote agents, these flaws increase risk because untrusted peers may trigger resource exhaustion or expose process memory contents through crafted websocket traffic.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: axios==1.13.4 — 16 advisory(ies): CVE-2026-44494 (axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co); CVE-2026-44495 (axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut); CVE-2025-62718 (Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF) +13 more

High
Category
Supply Chain
Confidence
98% confidence
Finding

The package declares axios 1.13.4, which the finding reports as having multiple known advisories, including SSRF-related and prototype-pollution-enabled attack paths. In this skill's context—an agent commerce CLI that likely performs network requests, handles wallets, discovers marketplace agents, and transacts with remote services—a vulnerable HTTP client materially increases risk of credential leakage, request manipulation, SSRF, or response hijacking when interacting with untrusted endpoints.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README encourages users and agents to launch tokens and register marketplace offerings, which can trigger real financial, reputational, or irreversible on-chain actions, but it provides no warning, confirmation guidance, or risk framing. In an agent-skill context, this is more dangerous because autonomous or semi-autonomous agents may treat these commands as routine operations and execute them without adequate human review.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README instructs users to store an API key and session token in a local config.json file but does not warn about secret exposure, local file permissions, backup leakage, or accidental disclosure through tooling. This is especially risky for an agent-integrated skill because agents and surrounding tooling may read, log, copy, or exfiltrate workspace files, turning undocumented credential storage into a practical secret-handling weakness.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill documents use of environment-backed credentials and networked CLI operations but does not declare any explicit tool scope or permission boundaries. In an agent setting, missing scope declarations can lead to overbroad execution authority and make it harder for users or orchestrators to constrain file, env, and network access safely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The setup instructions say to run an authentication flow that generates and writes an API key to repo-local config.json, but they do not prominently warn about credential persistence, local exposure risk, or accidental commit/leakage. In agent or shared-repo environments, silently writing credentials to a workspace file can lead to theft of ACP account access and downstream financial or operational abuse.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill exposes a token launch command for fundraising and revenue but does not provide a strong warning that this is an irreversible or high-consequence financial/public operation. Users may trigger token issuance without understanding fees, legal/compliance implications, reputational risk, and on-chain permanence.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The seller runtime is described as automatically accepting and processing jobs by executing user-defined handlers, yet the documentation does not clearly warn that this can trigger arbitrary local code paths and network actions without per-job human review. In context, this is especially risky because the skill is designed to interact with external marketplace participants and could continuously process adversarial inputs.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
src/commands/serve.ts:86

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
src/commands/setup.ts:52

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
src/lib/config.ts:142

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
src/lib/open.ts:20