Back to skill

Security audit

Virtuals Protocol Acp Egip31

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent ACP marketplace CLI, but it needs Review because it combines financial/agent-commerce actions with plaintext credential storage, a long-running seller process, and confirmed unsafe local path handling.

Install only if you intend to let this agent transact through Virtuals ACP. Keep config.json private, avoid shared or indexed workspaces, review every token/job/seller action before execution, do not run seller offerings from untrusted names, and upgrade dependencies plus fix path validation before using it with valuable wallets or autonomous services.

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
src/commands/sell.ts:57
Finding
Path Traversal Allows File Creation Outside Seller Directories<![CDATA[ ## Vulnerability Details **File Location**: `src/commands/sell.ts:57-58`, `src/commands/sell.ts:242-281`, `src/commands/sell.ts:594-595`, and `src/commands/sell.ts:638-664` **Vulnerability Type**: Unvalidated path input leading to arbitrary file creation or overwrite **Risk Level**: High ### Vulnerable Code ```ts function resolveOfferingDir(offeringName: string): string { return path.resolve(OFFERINGS_ROOT, offeringName); } ``` ```ts export async function init(offeringName: string): Promise<void> { if (!offeringName) { output.fatal("Usage: acp sell init <offering_name>"); } const dir = resolveOfferingDir(offeringName); if (fs.existsSync(dir)) { output.fatal(`Offering directory already exists: ${dir}`); } fs.mkdirSync(dir, { recursive: true }); const offeringJson: Record<string, unknown> = { 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<ExecuteJobResult> { // 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); } ``` The same issue exists in resource creation: ```ts function ...[truncated 4316 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict offering and resource names to a safe identifier format: ```ts function validateArtifactName(name: string): void { if (!/^[A-Za-z0-9_-]+$/.test(name)) { throw new Error( "Name may contain only letters, numbers, underscores, and hyphens." ); } } ``` 2. Verify containment after path resolution: ```ts function resolveWithinRoot(root: string, name: string): string { validateArtifactName(name); const candidate = path.resolve(root, name); const relative = path.relative(root, candidate); if ( relative === "" || relative.startsWith("..") || path.isAbsolute(relative) ) { throw new Error("Resolved path is outside the permitted directory."); } return candidate; } ``` 3. Apply the same validation to: - `resolveOfferingDir` - `resolveResourceDir` - `loadOffering` - Any command that accepts an offering or resource name 4. Before dynamically importing an offering handler, require the name to match a locally registered allowlist and verify the real path remains beneath the offerings root. Where symbolic links are possible, compare canonical paths obtained through `fs.realpathSync`. 5. Avoid using remote job data directly as a filesystem selector. Resolve the remote offering name through a map of known local offering identifiers instead. 6. Add tests covering: - `../` traversal - Absolute paths - Backslash traversal on Windows - Symbolic-link escapes - Empty names and separator-only names ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/lib/config.ts:35
Finding
Session Tokens and API Keys Are Stored Without Enforced Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `src/lib/config.ts:35-50` **Vulnerability Type**: Insecure plaintext credential storage and file permissions **Risk Level**: Medium ### Vulnerable Code ```ts export function readConfig(): ConfigJson { if (!fs.existsSync(CONFIG_JSON_PATH)) { return {}; } try { const content = fs.readFileSync(CONFIG_JSON_PATH, "utf-8"); return JSON.parse(content); } catch { return {}; } } export function writeConfig(config: ConfigJson): void { try { fs.writeFileSync(CONFIG_JSON_PATH, JSON.stringify(config, null, 2) + "\n"); } catch (err) { console.error(`Failed to write config.json: ${err}`); } } ``` Sensitive values are passed to this function from authentication and agent setup code: ```ts export function storeSessionToken(token: string): void { const config = readConfig(); writeConfig({ ...config, SESSION_TOKEN: { token } }); } ``` ```ts writeConfig({ ...config, LITE_AGENT_API_KEY: result.apiKey, agents: updatedAgents, }); ``` ### Technical Analysis `config.json` contains reusable authentication material, including: - ACP session bearer tokens - `LITE_AGENT_API_KEY` - Per-agent API keys retained in the `agents` array `fs.writeFileSync` is called without an explicit file mode. For a newly created file, Node.js uses the default creation mode subject to the process umask. On systems with a permissive or misconfigured umask, the resulting file may be readable by other local users or processes. If `config.json` already exists with overly broad permissions, rewriting it does not correct those permissions. The project documentation warns against committing the file, but source-control exclusion does not protect it from local disclosure, backups, workspace indexing, or other processes running under different accounts. The observed network transmission itself is consistent with the declared functionality: session tokens are sent to `https://acpx.virtuals.io`, and API key ...[truncated 1580 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the credential file with owner-only permissions: ```ts export function writeConfig(config: ConfigJson): void { const serialized = JSON.stringify(config, null, 2) + "\n"; fs.writeFileSync(CONFIG_JSON_PATH, serialized, { encoding: "utf-8", mode: 0o600, }); fs.chmodSync(CONFIG_JSON_PATH, 0o600); } ``` 2. Use atomic writes to reduce corruption and permission inconsistencies: ```ts const tempPath = `${CONFIG_JSON_PATH}.tmp-${process.pid}`; fs.writeFileSync(tempPath, serialized, { encoding: "utf-8", mode: 0o600, flag: "wx", }); fs.renameSync(tempPath, CONFIG_JSON_PATH); fs.chmodSync(CONFIG_JSON_PATH, 0o600); ``` 3. Check permissions when reading an existing file and either correct insecure permissions or refuse to use the file until the user fixes them. 4. Prefer an operating-system credential store or dedicated secret manager rather than storing bearer tokens and API keys in the repository directory. 5. Keep non-sensitive state, such as seller PID and agent display metadata, separate from secret credentials. 6. Ensure `config.json`, temporary credential files, logs, backups, and editor swap files are excluded from source control and protected from workspace-wide indexing. 7. Document credential rotation and revocation procedures in case the configuration file is exposed. ]]>
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 (53)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documented behavior includes local filesystem writes to config.json, environment/API-key handling, and local state changes, which are materially different from a pure marketplace client. When a skill's description focuses on ACP commerce but underplays local secret storage and host-side mutation, agents may run it in contexts where such side effects are unexpected and risky.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented behavior includes local filesystem writes to config.json, environment/API-key handling, and local state changes, which are materially different from a pure marketplace client. When a skill's description focuses on ACP commerce but underplays local secret storage and host-side mutation, agents may run it in contexts where such side effects are unexpected and risky.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documented behavior includes local filesystem writes to config.json, environment/API-key handling, and local state changes, which are materially different from a pure marketplace client. When a skill's description focuses on ACP commerce but underplays local secret storage and host-side mutation, agents may run it in contexts where such side effects are unexpected and risky.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented behavior includes local filesystem writes to config.json, environment/API-key handling, and local state changes, which are materially different from a pure marketplace client. When a skill's description focuses on ACP commerce but underplays local secret storage and host-side mutation, agents may run it in contexts where such side effects are unexpected and risky.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The documented behavior includes local filesystem writes to config.json, environment/API-key handling, and local state changes, which are materially different from a pure marketplace client. When a skill's description focuses on ACP commerce but underplays local secret storage and host-side mutation, agents may run it in contexts where such side effects are unexpected and risky.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The documented behavior includes local filesystem writes to config.json, environment/API-key handling, and local state changes, which are materially different from a pure marketplace client. When a skill's description focuses on ACP commerce but underplays local secret storage and host-side mutation, agents may run it in contexts where such side effects are unexpected and risky.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documented behavior includes local filesystem writes to config.json, environment/API-key handling, and local state changes, which are materially different from a pure marketplace client. When a skill's description focuses on ACP commerce but underplays local secret storage and host-side mutation, agents may run it in contexts where such side effects are unexpected and risky.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documented behavior includes local filesystem writes to config.json, environment/API-key handling, and local state changes, which are materially different from a pure marketplace client. When a skill's description focuses on ACP commerce but underplays local secret storage and host-side mutation, agents may run it in contexts where such side effects are unexpected and risky.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documented behavior includes local filesystem writes to config.json, environment/API-key handling, and local state changes, which are materially different from a pure marketplace client. When a skill's description focuses on ACP commerce but underplays local secret storage and host-side mutation, agents may run it in contexts where such side effects are unexpected and risky.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding
The documented behavior includes local filesystem writes to config.json, environment/API-key handling, and local state changes, which are materially different from a pure marketplace client. When a skill's description focuses on ACP commerce but underplays local secret storage and host-side mutation, agents may run it in contexts where such side effects are unexpected and risky.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The documented behavior includes local filesystem writes to config.json, environment/API-key handling, and local state changes, which are materially different from a pure marketplace client. When a skill's description focuses on ACP commerce but underplays local secret storage and host-side mutation, agents may run it in contexts where such side effects are unexpected and risky.

Ae1

High
Category
analysis-evasion
Content
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
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
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
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

High
Confidence
97% confidence
Finding
The skill presents token launch as a routine command without a clear warning that it may create irreversible on-chain transactions, incur fees, affect fundraising/compliance posture, and expose the user to financial loss. Financially consequential blockchain actions require strong consent and risk disclosure because mistakes cannot easily be undone.

Missing User Warnings

High
Confidence
96% confidence
Finding
The seller runtime is described as automatically accepting requests, requesting payment, and delivering results by executing handlers, but there is no corresponding warning about autonomous external interactions or the risk of unsafe handler execution. In context, this is more dangerous because the skill is specifically designed to expose capabilities to external parties and monetize execution, which amplifies abuse, fraud, and unintended actions if handlers are weak or overprivileged.

Ae1

High
Category
analysis-evasion
Content
- **Repo root** — `SKILL.md`, `package.json`, `config.json` (do not commit). Run all commands from here.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- **bin/acp.ts** — Unified CLI entry point. Invoke with `acp <command> [subcommand] [args] --json`.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

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
96% confidence
Finding
The lockfile pins axios 1.13.4, which is reported with multiple advisories including SSRF and prototype-pollution-related exploitation paths. In this skill, axios is a direct runtime dependency and the skill explicitly interacts with external agents and network endpoints, which increases the likelihood that attacker-controlled URLs, redirects, proxy settings, or response handling could be involved.

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
84% confidence
Finding
form-data 4.0.5 is reported as vulnerable to CRLF injection through unescaped multipart field names and filenames. If this skill ever constructs multipart requests using untrusted values from agent marketplace metadata, uploaded artifacts, or user-controlled inputs, an attacker may be able to manipulate request structure or smuggle unexpected headers/content.

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
92% confidence
Finding
socket.io-parser 4.2.5 is flagged for unbounded attachment handling and memory exhaustion conditions. Since this skill uses socket.io-client to interact with remote parties, a malicious peer or server could send crafted payloads that consume excessive memory and destabilize the agent process, causing denial of service.

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
91% confidence
Finding
ws 8.18.3 is reported with memory disclosure and memory exhaustion issues. Because this package underlies real-time network communication with external systems, a hostile server or intermediary could exploit frame fragmentation or protocol handling weaknesses to crash the client, exhaust memory, or potentially expose sensitive process data.

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
This package depends on axios 1.13.4, which the finding identifies as having multiple known advisories, including SSRF and prototype-pollution-related exploitation paths. In this skill's context, the agent interacts with external services, wallets, marketplaces, and other agents, so a vulnerable HTTP client is more dangerous because it may handle untrusted URLs, proxy settings, credentials, and responses in security-sensitive network flows.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The README states that sensitive credentials such as an API key and session token are stored in a local config.json file, but it does not warn users to protect that file, restrict permissions, or avoid sharing it. In the context of a tool that manages wallets, marketplace actions, and token-launch capability, theft of this file could let an attacker impersonate the agent account and perform unauthorized actions.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill declares operational capabilities that involve environment access, network use, local config handling, and process/runtime management, but it does not declare any tool scope or permissions boundary. That omission makes it harder for a host agent or reviewer to understand and constrain what the skill may do, increasing the risk of overbroad execution and accidental misuse.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill tells the agent to run setup that performs authentication and writes an API key into config.json, but it does not prominently warn about credential storage, persistence, file permissions, or leakage risk. This is dangerous because secrets may be stored in the repo directory, exposed to other tools or commits, or handled without informed user consent.

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