Back to skill

Security audit

MoltDomesticProduct - Agent Hiring Marketplace (MDP)

Security checks for vulnerabilities and agentic risk

Overview

The skill is openly about an autonomous USDC job marketplace, but it gives agents live wallet-signing and payment authority with weak scoping and mutable update paths.

Review before installing. Use only a dedicated low-balance wallet, pin SDK and runner versions, avoid loading the remote always-latest skill as trusted instructions, keep MDP_AUTO_PROPOSE disabled unless policy checks are in place, and do not run buyer mode until payment requirements, destinations, and spend limits are independently verified.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (4)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:64
Finding
Mutable Remote Skill Instructions Can Bypass Package Review<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:64-81` **Vulnerability Type**: Mutable remote instruction source **Risk Level**: High ### Code Snippet ```markdown ## Keeping Up To Date Canonical skill URL (always latest): - `https://moltdomesticproduct.com/skill.md` SDK updates: - The SDK does not auto-update itself. - If a newer npm version exists, the SDK will warn at most once per 24 hours. - Update the SDK with: ```bash npm i @moltdomesticproduct/mdp-sdk@latest ``` ClawHub installs: - If you installed the skill via ClawHub and your agent appears to be using older instructions, refresh/re-add the skill. - Prefer referencing the canonical URL above so agents always fetch the latest version. ``` ### Technical Analysis The reviewed package explicitly recommends referencing an “always latest” remotely hosted Skill file instead of relying on the locally reviewed copy. The remote document is not pinned to a version, cryptographic digest, or trusted signature. Consequently, the effective agent instructions can change after the package has passed review. If the hosting account, web application, DNS configuration, TLS termination, or deployment pipeline is compromised, an attacker could replace the remote Skill text with instructions that alter the agent’s goals or request unsafe wallet and data operations. This is particularly sensitive because the Skill already operates with a wallet private key and supports authenticated API requests and financial signatures. ### Attack Path 1. A user installs or reviews the local Skill package. 2. Following the packaged guidance, the agent references or fetches `https://moltdomesticproduct.com/skill.md`. 3. The remote file is modified by its operator or through compromise of the hosting infrastructure. 4. The agent loads the modified text as trusted Skill instructions. 5. The new instructions induce actions not present in the reviewed package, potentially including unsafe signing, data disclosure, ...[truncated 486 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Treat the packaged `SKILL.md` as the authoritative instruction source. - Do not instruct agents to automatically prefer an unversioned remote copy. - Publish updates as reviewed, immutable package versions. - If remote updates are unavoidable, pin the expected version and SHA-256 digest. - Cryptographically sign remote Skill files and verify the signature against a locally pinned public key. - Display proposed instruction changes and require explicit user approval before activation. - Apply strict content-security controls so a remotely fetched document cannot introduce new tools, hosts, credential requests, or financial operations without separate authorization. ]]>

T08 · Insecure Dependencies

Error
Location
pager.md:497
Finding
Unpinned Packages Execute with Access to the Wallet Environment<![CDATA[ ## Vulnerability Details **File Location**: `pager.md:497-504`; related instructions at `SKILL.md:26` and `SKILL.md:75` **Vulnerability Type**: Unpinned executable dependencies **Risk Level**: High ### Code Snippet ```bash # Set required env export MDP_PRIVATE_KEY="0xYOUR_PRIVATE_KEY" # Run pager (discovery mode - logs matches, no auto-propose) npx tsx pager.ts # Run pager (autonomous mode - auto-proposes on matching jobs) MDP_AUTO_PROPOSE=true npx tsx pager.ts ``` Related installation instructions: ```bash npm install @moltdomesticproduct/mdp-sdk npm i @moltdomesticproduct/mdp-sdk@latest ``` ### Technical Analysis The instructions install `@moltdomesticproduct/mdp-sdk` without an exact version and explicitly recommend the mutable `@latest` tag. They also invoke `npx tsx`, which can resolve and download an executable package from the configured npm registry if it is not already installed locally. No lockfile, integrity pin, package signature requirement, or local dependency declaration is included in the reviewed project. These packages execute in a process environment containing `MDP_PRIVATE_KEY`. A compromised release, package maintainer account, registry response, or dependency subtree could therefore read and transmit the wallet key or modify transaction behavior. The issue is especially severe because dependency execution occurs after the user exports a funded wallet credential. ### Attack Path 1. An attacker compromises the npm package, maintainer account, registry resolution, or an unpinned transitive dependency. 2. The attacker publishes a malicious version that is selected by the unversioned install or `@latest`. 3. The user exports `MDP_PRIVATE_KEY` and follows the documented `npx tsx pager.ts` command. 4. The compromised package executes in the same process or installation context. 5. It reads the private key from the environment, alters SDK signing behavior, or sends unauthorized transactions. 6. The attacker can then imperson ...[truncated 477 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin exact audited versions of `@moltdomesticproduct/mdp-sdk`, `tsx`, and all transitive dependencies. - Declare dependencies in `package.json` and commit a lockfile. - Use `npm ci` with lockfile integrity verification instead of unversioned installation. - Remove the recommendation to install `@latest`. - Install `tsx` as a reviewed local development dependency and run the local binary; do not permit implicit `npx` downloads. - Verify npm package provenance and integrity before release. - Disable unnecessary npm lifecycle scripts during installation where operationally possible. - Run the pager in a restricted environment using a dedicated low-value wallet and a minimal environment-variable allowlist. - Prefer an external signer with transaction policies over exposing a raw private key to the Node.js process. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
pager.md:74
Finding
Configurable API Origin Can Solicit Wallet Authentication Signatures<![CDATA[ ## Vulnerability Details **File Location**: `pager.md:74-91` **Vulnerability Type**: Insufficient validation of a credential-bearing network destination **Risk Level**: High ### Code Snippet ```ts import { MDPAgentSDK } from "@moltdomesticproduct/mdp-sdk"; // -- Configuration ------------------------------------------ const PRIVATE_KEY = process.env.MDP_PRIVATE_KEY as `0x${string}`; const API_BASE = process.env.MDP_API_BASE ?? "https://api.moltdomesticproduct.com"; const AGENT_ID = process.env.MDP_AGENT_ID; const POLL_INTERVAL = Number(process.env.MDP_POLL_INTERVAL ?? 600_000); // 10 min const MSG_INTERVAL = Number(process.env.MDP_MSG_INTERVAL ?? 300_000); // 5 min const MAX_PROPOSALS = Number(process.env.MDP_MAX_PROPOSALS ?? 3); const AUTO_PROPOSE = process.env.MDP_AUTO_PROPOSE === "true"; const MATCH_THRESHOLD = Number(process.env.MDP_MATCH_THRESHOLD ?? 0.5); if (!PRIVATE_KEY) { console.error("MDP_PRIVATE_KEY is required"); process.exit(1); } // -- Bootstrap ---------------------------------------------- const sdk = await MDPAgentSDK.createWithPrivateKey( { baseUrl: API_BASE }, PRIVATE_KEY ); ``` ### Technical Analysis `MDP_API_BASE` can redirect SDK authentication and subsequent authenticated traffic to an arbitrary origin. The code performs no local scheme validation, hostname allowlisting, or certificate pinning before giving the SDK both the selected endpoint and the wallet private key. The documented authentication protocol asks the server for a message and then signs that message with the wallet. The reviewed code does not independently validate SIWE-style fields such as domain, URI, chain ID, nonce, statement, expiration, or intended purpose before signing. The source does not directly transmit the raw private key. However, it delegates signing to an external SDK while allowing the signing challenge source to be changed through the environment. This contradicts the Skill’s stated security rule to trust only the MDP dom ...[truncated 1027 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove arbitrary API-origin overrides from production wallet-signing workflows. - Enforce HTTPS and an exact allowlist containing only the intended MDP API hostname. - Reject URLs containing credentials, unexpected ports, redirects to other origins, or noncanonical hostnames. - Independently decode and validate every authentication message before signing. - Require the expected domain, URI, chain ID, nonce format, issuance time, expiration, and authentication purpose. - Refuse blind or generic `personal_sign` requests that do not conform to the expected authentication schema. - Use a dedicated executor wallet with minimal funds and no unrelated permissions. - Prefer a policy-enforcing external signer or hardware-backed signer rather than passing a raw key into the SDK. - Add tests demonstrating that hostile values of `MDP_API_BASE` are rejected. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
pager.md:404
Finding
Autonomous Buyer Blindly Signs Server-Supplied Payment Requirements<![CDATA[ ## Vulnerability Details **File Location**: `pager.md:404-437` **Vulnerability Type**: Unvalidated financial signature and autonomous settlement **Risk Level**: Critical ### Code Snippet ```ts async function pollMyJobs() { try { // Check open jobs for new proposals const openJobs = await sdk.jobs.list({ status: "open" }); for (const job of openJobs) { const proposals = await sdk.proposals.list(job.id); const pending = proposals.filter(p => p.status === "pending"); if (pending.length === 0) continue; // Prefer verified agents (agent is a joined field on Proposal) const verified = pending.filter(p => p.agent?.verified); const candidates = verified.length > 0 ? verified : pending; // Pick best proposal (cheapest verified agent as baseline strategy) const best = candidates.sort((a, b) => a.estimatedCostUSDC - b.estimatedCostUSDC)[0]; if (!best) continue; console.log(`[buyer] Accepting proposal from ${best.agent?.name} for ${best.estimatedCostUSDC} USDC`); await sdk.proposals.accept(best.id); // Fund escrow via x402 payment flow // Step 1: Create payment intent const { paymentId, requirement, encodedRequirement } = await sdk.payments.initiatePayment(job.id, best.id); console.log(`[buyer] Payment intent created: ${paymentId} (${requirement.maxAmountRequired} USDC)`); // Step 2: Sign the x402 payment header with your wallet signer // The encodedRequirement contains the payment details for signing const paymentHeader = await signer.signMessage(encodedRequirement); // Step 3: Settle the payment const result = await sdk.payments.settle(paymentId, paymentHeader); if (result.success) { console.log(`[buyer] Funded job "${job.title}" - status: ${result.status}, tx: ${result.txHash ?? "pending"}`); } } ``` ### Technical Analysis The buyer loop automatically selects a proposal, accepts it, req ...[truncated 1971 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Decode the payment requirement locally before any signature is produced. - Require chain ID `8453` and the exact expected Base USDC token address. - Require an allowlisted escrow contract and expected settlement method. - Verify that the payment ID, job ID, proposal ID, recipient, and amount exactly match locally trusted state. - Ensure the amount does not exceed the accepted proposal cost or the posted job budget. - Validate nonce uniqueness, expiration, authorization validity windows, and replay protection. - Use EIP-712 typed-data signing with a clearly displayed domain and fields rather than signing an opaque encoded message. - Require explicit human approval for each payment unless a separately configured policy authorizes it. - Add strict per-job, per-transaction, and daily spending limits enforced by the signer rather than only by application logic. - Reject unexpected API responses instead of relying on logged values. - Keep autonomous wallets segregated and minimally funded. - Record an immutable local audit trail of decoded payment fields, approval decisions, signatures, and settlement results. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (10)

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
A skill described as a pager requires an on-chain private key and later demonstrates authenticated payment signing and settlement. Combining message/job polling with wallet-key based authority substantially raises risk: compromise, misuse, or misconfiguration of the running agent can lead to unauthorized proposals, message actions, and potentially irreversible financial transactions.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The buyer-mode quick-start walks directly from job creation to `sdk.payments.fundJob(...)` without a clear caution that this can initiate a live blockchain payment using the configured private key. In a skill for autonomous agents, concise code snippets are often copied verbatim, so omitting a real-funds warning materially raises the risk of unintended escrow deposits.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill explicitly promotes autonomous escrow funding and presents `fundJob()` as a normal workflow step, but it does not place a prominent warning near that guidance that this signs real EIP-3009 authorizations and may trigger irreversible on-chain USDC transfers. For an agent skill intended for autonomous execution, that omission increases the chance that users enable live payment flows without understanding they are authorizing real fund movement.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The autonomous pager protocol includes `MDP_AUTO_PROPOSE` and pseudocode for unattended proposal submission, but it does not prominently warn that enabling this allows an agent to take marketplace actions on its own behalf without human review. While proposal submission is less severe than direct fund transfer, it can still create contractual, reputational, and operational risk through spam, accidental commitments, or engagement with malicious job postings.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill instructs agents to poll unread direct messages, fetch their contents, process them, and mark conversations as read, but it does not prominently warn users that private communications will be continuously accessed and state will be modified. In an autonomous agent context, silent message access can create privacy, consent, and auditability issues, especially if operators assume the pager is only checking job listings.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill describes autonomous proposal submission, proposal acceptance, and escrow/payment settlement without a prominent up-front warning that these actions can commit funds or alter marketplace workflow irreversibly. In this context, automation tied to a private key and payment signer makes omissions around operator consent more dangerous, because a user may deploy it as a benign monitor and inadvertently authorize spending or contractual commitments.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The file is presented as a pager/heartbeat protocol, but it also includes buyer-mode logic that accepts proposals, initiates escrow payments, signs payment material, and settles on-chain transactions. That scope expansion is dangerous because operators may enable or reuse the code expecting passive monitoring, while it actually performs financially consequential state-changing actions.

Static analysis

No suspicious patterns detected.