T03 · Remote Payload Retrieval and Execution
- Location
scripts/deploy-contracts.ts:6- Finding
Unpinned Remote Script Piped Directly into a Shell
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
SafeLink has a coherent payments-and-agent-hiring purpose, but the reviewed artifacts expose high-impact wallet, payment, and deployment risks that need human review before installation.
Review this before installing, especially if you would use real funds or mainnet. Use only testnet funds, avoid storing long-lived secrets in the generated .env, do not run the documented curl-to-bash command, inspect or patch the deployment script, and treat Coinbase wallet export output as sensitive secret material. Do not use the x402 or escrow flows with valuable wallets until recipient/amount validation, allowance limits, and credential handling are hardened.
scripts/deploy-contracts.ts:6Unpinned Remote Script Piped Directly into a Shell
scripts/deploy-contracts.ts:78Shell Command Injection Through BASE_RPC_URL
src/payments/x402.ts:124Facilitator-Controlled USDC Recipient and Amount Are Signed Without Validation
src/payments/escrow.ts:196Unlimited USDC Allowance Exceeds the Required Escrow Privilege
scripts/generate-env.ts:260Sensitive Credentials Stored in .env Without Enforced Restrictive Permissions
src/wallet/coinbase.ts:168Coinbase Wallet Export Material Is Printed and Partially Logged
scripts/deploy-contracts.ts:55Unpinned Forge and npm Dependencies Create Mutable Supply-Chain Inputs
src/security/input-gate.ts:190DNS Rebinding Gap Between Endpoint Validation and Subsequent Connection
The declared description presents a production A2A operational skill centered on secure hiring/execution flows and runtime protections. This code chunk instead serves as a DevOps/deployment script for smart contracts. While it does relate loosely to ERC-8004 registry and escrow contracts mentioned in the description, its primary behavior is contract build/test/deploy automation on Base and local config updates. It also uses a deployer private key directly, which differs from the declared emphasis on MPC wallet signing for operations. The advanced runtime capabilities in the description—x402 payments, replay protection, DNS-safe validation, policy gating, and risk scoring—are not implemented or evidenced here. Therefore the description does not accurately represent what this code chunk actually does.
The declared description presents a runtime security/transaction skill for agent-to-agent hiring and settlement workflows. The supplied code does not implement escrow, hiring/execution logic, x402 payments, ERC-8004 checks, DNS-safe endpoint validation, MPC signing, or replay protection enforcement. Instead, it is a developer setup utility whose primary purpose is environment configuration: collecting API keys and settings, testing connectivity to external services, warning about mainnet usage, and writing a .env file. While some configured variables relate to the broader system described (e.g., x402 facilitator URL, Redis for replay protection, Privy wallet provider), this code chunk itself only performs setup and validation, not the declared secure A2A workflow behavior.
The code substantially supports part of the description: escrowed settlement, proof-before-settlement via proofCommitment/proofHash, risk-scored transactions, approval/policy gating, and MPC wallet signing. However, the declared description presents a broader production A2A hiring/execution skill with several specific security and payment capabilities that are not implemented in this chunk. The code is narrowly focused on escrow payment lifecycle management for a SafeEscrow contract using USDC, including allowance handling, simulation, risk gating, release/refund, and escrow state reads. There is no evidence here of x402 facilitator payments, ERC-8004 identity/reputation checks, replay protection, DNS-safe endpoint validation, or general A2A hiring/execution workflow behavior. Because those are prominent declared capabilities rather than minor implementation details, the description overstates what this code chunk actually does.
The description presents a broad production A2A hiring/execution skill with multiple security and trust features. The supplied code chunk is much narrower: it handles x402 payment requirement retrieval, validates facilitator-returned chainId/token/deadline, signs a USDC TransferWithAuthorization payload via MPC wallet, submits it to a facilitator, and verifies receipts. MPC wallet signing and x402 facilitator payments do align with the description, and there is some defensive validation. However, most of the declared core capabilities are not represented in this code chunk, especially escrow, identity/reputation checks, DNS-safe endpoint validation, policy gating, and risk scoring. Because the declared purpose materially overstates the implemented behavior of the provided code, this is a mismatch.
The supplied code is narrowly focused on MPC wallet operations: selecting a wallet provider, creating/loading a wallet, sending EVM transactions, signing typed data and messages, and exposing the agent address. While MPC wallet signing is indeed present and aligns with one part of the description, the majority of the declared purpose is not represented in this code chunk. There is no evidence of escrow logic, hiring/execution workflow handling, x402 payments, ERC-8004 identity or reputation validation, DNS-safe endpoint checks, explicit replay-protection mechanisms beyond ordinary transaction nonce usage, policy gating, or risk scoring. Because the declared description presents a much broader secure A2A execution/hiring skill and this code only implements wallet functionality, the description does not accurately represent what this specific code chunk actually does.
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).
Base RPC endpoint), ERC8004_REGISTRY_ADDRESS (after deploy), SAFE_ESCROW_ADDRESS (after deploy), X402_FACILITATOR_URL (default: https://x402.org/facilitator)"
required_env_wallet: "One of: COINBASE_CDP_API_KEY_NAME + COINBASE_CDP_API_KEY_PRIVATE_KEY (Coinbase AgentKit) OR PRIVY_APP_ID + PRIVY_APP_SECRET (Privy MPC). Both are MPC providers — private keys never enter app memory."
required_env_llm: "ANTHROPIC_API_KEY (when LLM_PROVIDER=anthropic, default) OR LLM_BASE_URL + LLM_API_KEY (when LLM_PROVIDER=openai_compatible)"
optional_env: "REDIS_URL (multi-instance replay store), TENDERLY_ACCESS_KEY (simulation), BASESCAN_API_KEY (explorer), TASK_AUTH_SHARED_SECRET (>=32 chars, when TASK_AUTH_REQUIRED=true), SIWX_VERIFIER_URL (when SIWX_REQUIRED=true), AUTONOMYS_RPC_URL (memory checkpoints)"
deploy_only_env: "DEPLOYER_PRIVATE_KEY — used once by scripts/deploy-contracts.ts to deploy on-chain contracts. NOT loaded at MCP runtime. Use a throwaway funded key; discard after deploymen
Referenced artifact was not completely inspected
runtime_files: "scripts/generate-env.ts writes .env interactively on first setup. scripts/deploy-contracts.ts writes deployed contract addresses back to .env af
Referenced artifact was not completely inspected
runtime_files: "scripts/generate-env.ts writes .env interactively on first setup. scripts/deploy-contracts.ts writes deployed contract addresses back to .env af
The skill requires and documents handling of multiple secrets in .env, including API credentials and a deployer private key for one-time contract deployment. Even though the file says the deployer key is not used at runtime, combining secret collection, local file writes, and agent-accessible environment usage materially increases the blast radius if the host, setup scripts, or logs are compromised.
optional_env: "REDIS_URL (multi-instance replay store), TENDERLY_ACCESS_KEY (simulation), BASESCAN_API_KEY (explorer), TASK_AUTH_SHARED_SECRET (>=32 chars, when TASK_AUTH_REQUIRED=true), SIWX_VERIFIER_URL (when SIWX_REQUIRED=true), AUTONOMYS_RPC_URL (memory checkpoints)"
deploy_only_env: "DEPLOYER_PRIVATE_KEY — used once by scripts/deploy-contracts.ts to deploy on-chain contracts. NOT loaded at MCP runtime. Use a throwaway funded key; discard after deployment."
runtime_network: "Opens HTTP server on TASK_SERVER_PORT (default 3402, bound to 127.0.0.1) only when safe_listen_for_hire tool is called."
runtime_files: "scripts/generate-env.ts writes .env interactively on first setup. scripts/deploy-contracts.ts writes deployed contract addresses back to .env after one-time deployment. Neither runs automatically."
security_test_note: "tests/stress/ files contain literal prompt-injection strings (e.g. Ignore all previous instructions) as adversarial test fixtures to verify the input-gate blocks them. These are not instructions."
homepage: "https://github.com/charliebot8888/SafeLink"
repository: "https://github.com/charliebot8888/SafeLink"
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.
deploy_only_env: "DEPLOYER_PRIVATE_KEY — used once by scripts/deploy-contracts.ts to deploy on-chain contracts. NOT loaded at MCP runtime. Use a throwaway funded key; discard after deployment."
runtime_network: "Opens HTTP server on TASK_SERVER_PORT (default 3402, bound to 127.0.0.1) only when safe_listen_for_hire tool is called."
runtime_files: "scripts/generate-env.ts writes .env interactively on first setup. scripts/deploy-contracts.ts writes deployed contract addresses back to .env after one-time deployment. Neither runs automatically."
security_test_note: "tests/stress/ files contain literal prompt-injection strings (e.g. Ignore all previous instructions) as adversarial test fixtures to verify the input-gate blocks them. These are not instructions."
homepage: "https://github.com/charliebot8888/SafeLink"
repository: "https://github.com/charliebot8888/SafeLink"
---
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.
deploy_only_env: "DEPLOYER_PRIVATE_KEY — used once by scripts/deploy-contracts.ts to deploy on-chain contracts. NOT loaded at MCP runtime. Use a throwaway funded key; discard after deployment."
runtime_network: "Opens HTTP server on TASK_SERVER_PORT (default 3402, bound to 127.0.0.1) only when safe_listen_for_hire tool is called."
runtime_files: "scripts/generate-env.ts writes .env interactively on first setup. scripts/deploy-contracts.ts writes deployed contract addresses back to .env after one-time deployment. Neither runs automatically."
security_test_note: "tests/stress/ files contain literal prompt-injection strings (e.g. Ignore all previous instructions) as adversarial test fixtures to verify the input-gate blocks them. These are not instructions."
homepage: "https://github.com/charliebot8888/SafeLink"
repository: "https://github.com/charliebot8888/SafeLink"
---
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.
deploy_only_env: "DEPLOYER_PRIVATE_KEY — used once by scripts/deploy-contracts.ts to deploy on-chain contracts. NOT loaded at MCP runtime. Use a throwaway funded key; discard after deployment."
runtime_network: "Opens HTTP server on TASK_SERVER_PORT (default 3402, bound to 127.0.0.1) only when safe_listen_for_hire tool is called."
runtime_files: "scripts/generate-env.ts writes .env interactively on first setup. scripts/deploy-contracts.ts writes deployed contract addresses back to .env after one-time deployment. Neither runs automatically."
security_test_note: "tests/stress/ files contain literal prompt-injection strings (e.g. Ignore all previous instructions) as adversarial test fixtures to verify the input-gate blocks them. These are not instructions."
homepage: "https://github.com/charliebot8888/SafeLink"
repository: "https://github.com/charliebot8888/SafeLink"
---
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).
rst MCP server for agent-to-agent hiring with on-chain escrow, x402 USDC micropayments, MPC wallets, ERC-8004 identity, and policy-gated transactions on Base.",
"tags": ["security", "web3", "a2a", "payments", "escrow", "x402", "erc-8004", "agentic-wallet", "mcp", "production"],
"requiredEnv": [
{
"name": "ANTHROPIC_API_KEY",
"description": "Claude Haiku key for task execution (LLM_PROVIDER=anthropic)",
"sensitive": true,
"required": "when LLM_PROVIDER=anthropic"
},
{
"name": "BASE_RPC_URL",
"description": "Base network RPC endpoint (default: https://sepolia.base.org)",
"sensitive": false,
"required": "always"
},
{
"name": "PRIVY_APP_ID",
"description": "Privy application ID for MPC wallet (WALLET_PROVIDER=privy)",
"sensitive": false,
"required": "when WALLET_PROVIDER=privy"
},
{
"name": "PRIVY_APP_SECRET",
"description": "Privy application secret for MPC wallet signing",
The documented prerequisite curl -L https://foundry.paradigm.xyz | bash is a classic pipe-to-shell pattern that executes remote content without integrity verification. If the remote endpoint, DNS, TLS trust chain, or distribution path is compromised, users could run arbitrary code on their machine, which is especially dangerous in a deployment workflow that also handles private keys.
* Deploy ERC8004Registry and SafeEscrow to Base (Sepolia or Mainnet based on BASE_RPC_URL).
*
* Prerequisites:
* 1. Install Foundry: curl -L https://foundry.paradigm.xyz | bash && foundryup
* 2. Set BASE_RPC_URL and DEPLOYER_PRIVATE_KEY in .env
* 3. Fund the deployer address with ETH on the target Base network
*
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
process.exit(1);
}
if (!process.env["DEPLOYER_PRIVATE_KEY"]) {
console.error(
"闂?DEPLOYER_PRIVATE_KEY not set in .env\n" +
" This is a ONE-TIME deploy key 闂?you can use a throwaway.\n" +
Repeating the same pipe-to-shell install command in an error message reinforces unsafe operator behavior and normalizes arbitrary remote script execution. Because this skill is for production A2A and contract deployment, the context increases risk: a compromised installer could steal wallet material, alter artifacts, or tamper with deployments.
} catch {
console.error(
"闂?Foundry not found.\n" +
" Install: curl -L https://foundry.paradigm.xyz | bash && foundryup"
);
process.exit(1);
}
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env tsx
/**
* SafeLink interactive .env setup wizard.
*
* Usage: npm run setup
*/
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env tsx
/**
* SafeLink interactive .env setup wizard.
*
* Usage: npm run setup
*/
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env tsx
/**
* SafeLink interactive .env setup wizard.
*
* Usage: npm run setup
*/
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env tsx
/**
* SafeLink interactive .env setup wizard.
*
* Usage: npm run setup
*/
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env tsx
/**
* SafeLink interactive .env setup wizard.
*
* Usage: npm run setup
*/
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env tsx
/**
* SafeLink interactive .env setup wizard.
*
* Usage: npm run setup
*/
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env tsx
/**
* SafeLink interactive .env setup wizard.
*
* Usage: npm run setup
*/
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import { fileURLToPath } from "url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const ENV_FILE = join(__dirname, "..", ".env");
const MAINNET_CONFIRM_PHRASE = "I_UNDERSTAND_MAINNET_RISK";
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import { fileURLToPath } from "url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const ENV_FILE = join(__dirname, "..", ".env");
const MAINNET_CONFIRM_PHRASE = "I_UNDERSTAND_MAINNET_RISK";
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });