Back to skill

Security audit

PayTrigo (OpenClawBot, Base/USDC)

Security checks for vulnerabilities and agentic risk

Overview

This payment skill is mostly coherent, but it embeds live payment API keys and can sign blockchain transactions with a user's wallet without enough validation or confirmation.

Install only after the publisher removes and rotates the embedded PayTrigo keys, requires user- or deployment-provided secrets, adds decoded transaction validation and explicit confirmation for bot payments, stops accepting raw private keys/passphrases on the command line, and pins dependencies with a lockfile. Use a dedicated low-balance wallet if testing.

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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/paytrigo.mjs:7
Finding
Hard-Coded Live PayTrigo API Credentials<![CDATA[ ## Vulnerability Details **File Location**: - `scripts/paytrigo.mjs:7-8` - `scripts/moltbot-human-flow.mjs:7-8` - `scripts/moltbot-bot-flow.mjs:8-9` **Vulnerability Type**: Hard-coded production credentials **Risk Level**: High ### Vulnerable Code ```js // scripts/paytrigo.mjs:7-8 const API_BASE = 'https://api.paytrigo.net'; const DEFAULT_API_KEY = 'sk_live_M4vDBePQLu8Uenl-b2_7_jMvh5y9sFi3FH9yuh0nwes'; ``` ```js // scripts/moltbot-human-flow.mjs:7-8 const API_BASE = 'https://api.paytrigo.net'; const API_KEY = 'sk_live_EQRe18nZCjXZSv8BmSJMs5mYvMOw1wgDd2RHnOH5T28'; ``` ```js // scripts/moltbot-bot-flow.mjs:8-9 const API_BASE = 'https://api.paytrigo.net'; const API_KEY = 'sk_live_EQRe18nZCjXZSv8BmSJMs5mYvMOw1wgDd2RHnOH5T28'; ``` The credentials are automatically placed into authorization headers: ```js const createHeaders = { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': idempotency, }; ``` ### Technical Analysis Two distinct live platform API keys are embedded directly in distributed source files. Any user who can download, inspect, cache, or obtain a copy of the Skill can recover these bearer credentials without authentication. Embedding a shared live credential prevents effective caller attribution, per-user revocation, secure rotation, and least-privilege access control. The keys are also transmitted whenever the scripts create invoices, so compromise of the source credential grants the same API access outside the Skill. This network use is necessary for the declared PayTrigo workflow, but distributing reusable platform credentials is not necessary and exceeds a minimum-privilege design. Each deployment should instead supply its own scoped credential through a protected secret channel. ### Attack Path 1. An attacker downloads or otherwise obtains the Skill source. 2. The attacker searches the scripts for `sk_live_` values. 3. The attacker extracts either hard-coded bearer credential. 4. The ...[truncated 723 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Revoke both exposed live keys immediately and review their API activity. 2. Remove all credentials from source code and repository history. 3. Require a credential through a protected environment variable, operating-system keychain, or secret manager. 4. Issue separate, narrowly scoped keys for each deployment or user. 5. Apply server-side restrictions such as permitted operations, recipient allowlists, rate limits, expiration, and usage monitoring. 6. Fail closed when no credential is configured; do not retain a shared fallback key. 7. Add secret-scanning checks to CI and pre-commit workflows. 8. Avoid writing credentials or authorization headers to logs and error messages. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/moltbot-bot-flow.mjs:154
Finding
Unvalidated Signing of API-Supplied Blockchain Transactions<![CDATA[ ## Vulnerability Details **File Location**: - `scripts/moltbot-bot-flow.mjs:154-163` - `scripts/moltbot-bot-flow.mjs:218-231` **Vulnerability Type**: Blind signing of remotely supplied transaction calldata **Risk Level**: Critical ### Vulnerable Code ```js const sendStep = async (wallet, step, label) => { const tx = await wallet.sendTransaction({ to: step.to, data: step.data, value: BigInt(step.value ?? '0'), }); console.log(`[${label}] txHash: ${tx.hash}`); const receipt = await tx.wait(); console.log(`[${label}] confirmed in block ${receipt.blockNumber}`); return tx.hash; }; ``` ```js const intent = await request( 'GET', `/v1/invoices/${invoice.invoiceId}/intent?chain=base&token=usdc`, undefined, intentHeaders, ); const provider = new JsonRpcProvider(rpcUrl); const wallet = (await getWallet()).connect(provider); if (!skipApprove && intent.steps?.approve) { await sendStep(wallet, intent.steps.approve, 'approve'); } const payTxHash = await sendStep(wallet, intent.steps.pay, 'pay'); ``` ### Technical Analysis The bot retrieves `approve` and `pay` transaction objects from a remote API and passes their `to`, `data`, and `value` fields directly to `wallet.sendTransaction()`. Before signing, the code does not validate: - The RPC network or expected Base chain ID. - The destination against known USDC and PayTrigo router addresses. - The ABI function selector. - The token covered by an approval. - The approval spender or allowance amount. - The expected payment recipient. - The payment amount encoded in calldata. - Whether native currency value must be zero. - Whether the returned transaction corresponds to the invoice that was created. TLS reduces ordinary interception risk but does not make remotely supplied calldata intrinsically safe. A compromised API, API account, DNS/TLS path, or upstream backend could return arbitrary transaction data. A malicious approval could grant an attacker an unlimited allowance, whil ...[truncated 1783 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Retrieve the provider network and require the exact expected Base mainnet chain ID before signing. 2. Maintain immutable allowlists for the canonical Base USDC contract and approved PayTrigo router. 3. Decode transaction calldata with a locally defined, minimal ABI. 4. Require the exact expected function selectors and reject all unknown methods. 5. Verify the token, spender, recipient, invoice identifier, amount, and deadline against locally constructed expectations. 6. Limit approval to the exact required amount; never accept an unlimited approval from the API. 7. Require native transaction value to be zero unless a narrowly documented operation explicitly requires otherwise. 8. Prefer constructing the transaction locally from validated invoice fields instead of signing opaque remote calldata. 9. Display a decoded transaction summary and require explicit confirmation for material payments. 10. Use a dedicated low-balance wallet with spending limits rather than a general-purpose wallet. 11. Abort on missing or additional transaction fields rather than attempting permissive execution. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/moltbot-human-flow.mjs:156
Finding
Checkout Authorization Tokens Disclosed Through Standard Output<![CDATA[ ## Vulnerability Details **File Location**: - `scripts/moltbot-human-flow.mjs:156-162` - `scripts/moltbot-bot-flow.mjs:210-216` **Vulnerability Type**: Sensitive authorization token exposure in logs **Risk Level**: Medium ### Vulnerable Code ```js // scripts/moltbot-human-flow.mjs:156-162 console.log('Invoice created'); console.log(JSON.stringify({ invoiceId: invoice.invoiceId, payUrl: invoice.payUrl, checkoutToken: invoice.checkoutToken, expiresAt: invoice.expiresAt, }, null, 2)); ``` ```js // scripts/moltbot-bot-flow.mjs:210-216 console.log('Invoice created'); console.log(JSON.stringify({ invoiceId: invoice.invoiceId, payUrl: invoice.payUrl, checkoutToken: invoice.checkoutToken, expiresAt: invoice.expiresAt, }, null, 2)); ``` The disclosed token is subsequently used as an authorization header: ```js const intentHeaders = { 'X-Checkout-Token': invoice.checkoutToken, }; ``` ### Technical Analysis The scripts print `checkoutToken` to standard output even though it is subsequently used as a bearer-style authorization value for invoice intent, submission, and status operations. Standard output is frequently retained by CI services, Agent transcripts, container logs, process supervisors, terminal capture systems, or centralized observability platforms. These destinations generally have a broader audience and longer retention period than in-process secrets. Printing the payment URL and invoice identifier may be required for the human workflow, but exposing the raw checkout token is not required for normal operation. ### Attack Path 1. A legitimate user or Agent executes the human or bot payment flow. 2. The complete checkout token is written to standard output. 3. A second user, compromised logging account, or log-collection service obtains the output. 4. The attacker combines the token with the printed invoice identifier. 5. The attacker uses the token against invoice intent, status, or payment-intent endpoints while the authori ...[truncated 567 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `checkoutToken` from all default console output. 2. Keep the token in memory for the duration of the process. 3. If persistence is required, store it in a dedicated mode-`0600` file or protected secret store. 4. Redact token values from error reports, Agent transcripts, telemetry, and debug logs. 5. Provide an explicit opt-in secure output option only if another process genuinely needs the token. 6. Make checkout tokens short-lived, invoice-scoped, and revocable on the server. 7. Review historical logs and remove any retained checkout tokens that remain valid. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/moltbot-bot-flow.mjs:98
Finding
Private Keys and Wallet Passphrases Accepted Through Process Arguments<![CDATA[ ## Vulnerability Details **File Location**: - `scripts/moltbot-bot-flow.mjs:98-123` - `scripts/moltbot-wallet-setup.mjs:83-94` - `README.md:20-24` - `README.md:89-93` - `SKILL.md:61-65` **Vulnerability Type**: Sensitive data exposure through command-line arguments **Risk Level**: High ### Vulnerable Code ```js const getPassphrase = async () => { if (args['passphrase-file']) { const value = (await readRequiredFile(args['passphrase-file'])).trimEnd(); if (!value) { fail('Passphrase file is empty.'); } return value; } if (args.passphrase) { return args.passphrase; } fail('Missing --passphrase or --passphrase-file (required to decrypt wallet)'); return ''; }; const getWallet = async () => { if (args.pk) { return new Wallet(args.pk); } const storeDir = args['store-dir'] ?? DEFAULT_STORE_DIR; const walletFile = args['wallet-file'] ?? resolve(storeDir, DEFAULT_WALLET_FILE); const walletJson = await readOptionalFile(walletFile); if (!walletJson) { fail('Missing --pk (or set --wallet-file / .openclawbot/wallet.json)'); } const passphrase = await getPassphrase(); return Wallet.fromEncryptedJson(walletJson, passphrase); }; ``` The unsafe form is explicitly documented: ```bash node scripts/moltbot-bot-flow.mjs bot --amount 0.001 --recipient 0xYourWallet... --pk 0xPRIVATE_KEY ``` The wallet setup script also accepts a passphrase from the argument list: ```js const getPassphrase = async () => { if (args['passphrase-file']) { const content = await readFileText(args['passphrase-file']); const trimmed = content.trimEnd(); if (!trimmed) { fail('Passphrase file is empty.'); } return trimmed; } if (args.passphrase) { return args.passphrase; } fail('Missing --passphrase or --passphrase-file'); return ''; }; ``` ### Technical Analysis Private keys and wallet-decryption passphrases can be supplied as `--pk` and `--passphrase` command-line arguments. Depending on ...[truncated 1657 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove support for `--pk` and `--passphrase` command-line values. 2. Remove all documentation examples that place private keys or passphrases in commands. 3. Prefer an operating-system keychain, hardware wallet, external signer, or secret manager. 4. If interactive use is necessary, read the passphrase from a non-echoing terminal prompt or standard input. 5. Continue supporting protected key and passphrase files, but verify restrictive ownership and permissions before reading them. 6. Warn users against retaining raw private-key files after encrypted import. 7. Use dedicated low-value wallets with limited balances for automated payments. 8. Ensure Agent and CI logs redact secrets and do not echo complete invocation arguments. ]]>

T08 · Insecure Dependencies

Warning
Location
package.json:5
Finding
Non-Reproducible Dependency Installation Without a Lockfile<![CDATA[ ## Vulnerability Details **File Location**: - `package.json:5-7` - `README.md:5-10` - `SKILL.md:20-24` **Vulnerability Type**: Unpinned third-party dependency resolution **Risk Level**: Medium ### Vulnerable Code ```json "dependencies": { "ethers": "^6.0.0" } ``` The documented installation command is: ```bash npm install ``` No package lockfile is present in the audited project structure. ### Technical Analysis The caret range permits npm to resolve different compatible `ethers` releases over time. Without a committed lockfile, the exact dependency graph, transitive versions, and integrity hashes are not fixed by the audited artifact. Consequently, future installations can execute or import package code that was not represented in this review. This is particularly important because `ethers` handles wallet decryption, private keys, transaction construction, signing, and RPC communication. No evidence was found that the declared `ethers` package is currently malicious or typosquatted. The confirmed weakness is non-reproducible and insufficiently constrained dependency installation, not a confirmed dependency compromise. ### Attack Path 1. A user follows the documentation and runs `npm install`. 2. npm resolves the broad version range and its transitive dependencies at installation time. 3. A future compromised, malicious, or unexpectedly incompatible release satisfies the allowed range. 4. The installation or runtime imports code that was not included in the audited repository. 5. Because the dependency is used for wallet and signing operations, compromised dependency code could access sensitive wallet material or alter transactions. ### Impact Assessment If dependency resolution is compromised, package code executes with the same local privileges as the Skill. In this project that process may access encrypted wallet files, decrypted wallet objects, passphrases held in memory, transaction data, and network connectivity. The present reposi ...[truncated 160 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Select and review a specific `ethers` release. 2. Generate and commit a package lockfile containing exact versions and integrity hashes. 3. Use `npm ci` in documented and automated installation workflows. 4. Enable dependency vulnerability, provenance, and integrity scanning in CI. 5. Review lockfile changes as security-sensitive code changes. 6. Use automated update tooling with controlled testing rather than unrestricted resolution during deployment. 7. Consider disabling lifecycle scripts during installation where operationally feasible. ]]>
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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (20)

Missing User Warnings

High
Confidence
99% confidence
Finding
The skill explicitly states that a platform API key is embedded in the helper script and promotes 'no-setup' immediate use. Embedding live credentials in distributable skill content is dangerous because any user or downstream agent can extract and abuse the key to create invoices, misuse platform resources, or impersonate legitimate payment activity.

Missing User Warnings

High
Confidence
95% confidence
Finding
The skill normalizes passing private keys on the command line and handling encrypted wallets/passphrase files without prominent safety guidance. Command-line private keys, local plaintext key files, and passphrase files are commonly exposed through shell history, process lists, logs, backups, or weak filesystem permissions, creating a realistic path to wallet compromise and fund theft.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The script hard-codes a live PayTrigo secret key directly in source, which exposes reusable production credentials to anyone who can read the file, logs, repository history, or packaged skill contents. Because this skill is explicitly designed to create payment invoices, the embedded key enables unauthorized API use, invoice creation, abuse of the merchant account, and possible downstream financial or operational damage.

Missing User Warnings

High
Confidence
97% confidence
Finding
After obtaining remote transaction instructions, the script immediately sends on-chain approve and pay transactions with the user's wallet and waits for confirmation, without any interactive confirmation or final review of recipient, amount, contract target, or calldata. In a payment skill context, this is especially dangerous because a mistaken invocation, compromised API response, or mis-specified recipient can directly cause irreversible loss of funds or unsafe token approvals.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The script embeds a live PayTrigo secret key directly in source code and uses it to create invoices against a production payment API. Any user who can read the skill, logs, repository, or packaged artifact can extract the credential and create or query payment objects on the associated account, leading to unauthorized API use, billing abuse, and broader account compromise.

Natural-Language Policy Violations

High
Confidence
99% confidence
Finding
A hard-coded live API credential in source code is a direct secret exposure vulnerability. Because this skill is specifically designed to create and verify PayTrigo payments, the exposed key is especially dangerous: anyone with access to the script can invoke privileged payment API operations in the production environment.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The script embeds and actively uses a live PayTrigo secret key, which gives anyone with access to the skill source immediate authenticated access to the payment API. In a payment-creation helper, this is especially dangerous because the key can be reused outside the intended workflow to create, inspect, or manipulate payment-related resources, and hard-coding prevents proper key rotation and scope control.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The README explicitly instructs users to pass a raw private key on the command line (`--pk 0xPRIVATE_KEY`). Command-line secrets are commonly exposed through shell history, process listings, terminal logging, CI logs, and remote session tooling, which can lead to full compromise of the payer wallet and theft of funds. In this skill’s context, the secret is a blockchain private key, so exposure is especially dangerous because transactions are irreversible.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
### 1) Create a passphrase file (local only)
```bash
echo "use-a-strong-passphrase" > passphrase.txt
chmod 600 passphrase.txt
```

### 2) Create a wallet (optionally set it as recipient)
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill advertises and instructs use of network and shell-capable scripts, but does not declare any tool scope or permission boundaries. That omission increases the chance an agent will run commands or make outbound requests without explicit user awareness, which is especially risky in a payment-handling skill.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The request helper sends invoice creation and payment-intent submission data to an external API, including recipientAddress, metadata, txHash, and payerAddress. The script contains no visible disclosure that these details will be transmitted to a third-party service, beyond the implementation itself.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The advertised capability includes payment verification, but the implemented flow only creates invoices, retrieves payment intents, signs blockchain transactions, and submits payment execution. This mismatch is security-relevant because users or orchestrators may invoke the skill expecting a read-only verification action, while the code performs state-changing financial operations that can spend funds.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The script performs a real payment-related API action as soon as the `human` command is run, creating a live invoice before any explicit confirmation prompt or strong warning. In an agent-skill context, this increases the risk of accidental or automated payment operations being triggered by misunderstood instructions, unsafe defaults, or adversarial task inputs.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The CLI accepts passphrases directly via --passphrase and private keys via --pk, which can expose secrets through shell history, process listings, terminal logging, CI job output, and agent telemetry. In an agent-driven payment skill, this is especially risky because wallet credentials protect real funds and may be handled in automated environments where command invocations are widely observable.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest describes a skill for creating or verifying PayTrigo payments on Base/USDC without webhooks, which suggests payment operations. This script instead creates new Ethereum wallets, imports private keys, encrypts them, and writes wallet, address, passphrase-derived, and recipient state to local files, which is a separate wallet provisioning/storage capability not described in the manifest.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
Creating random wallets and importing raw private keys are powerful key-management capabilities distinct from creating or verifying payments. A payment-focused skill may need to use an existing wallet, but provisioning and importing sensitive key material is not obviously required by the manifest's narrowly stated purpose.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The script's messaging implies the API key should come from PAYTRIGO_API_KEY, but the actual code always uses the embedded default key instead. This mismatch can mislead operators into thinking they control authentication through environment configuration when in reality the exposed built-in credential is always used, undermining secret management and incident response.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The script creates invoices and submits payment intent/status requests to a remote payment API, transmitting recipient addresses, transaction hashes, payer addresses, and metadata. Although these operations are central to the tool, the file provides no explicit user-facing warning or confirmation that payment-related data will be sent to an external service.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"private": true,
  "type": "module",
  "dependencies": {
    "ethers": "^6.0.0"
  }
}
Confidence
93% confidence
Finding
The dependency version for ethers is specified with a caret range, which permits automatic installation of newer minor and patch releases. This can introduce supply-chain risk or unexpected behavior changes if a compromised or incompatible release is published, especially in a payment-related skill that interacts with Base/USDC transactions.

Missing User Warnings

Low
Confidence
78% confidence
Finding
When --recipient is not supplied, the script automatically reads a recipient address from .openclawbot/recipient.txt or another provided file path. This local data access is not described in any warning or explanatory comment, which can surprise users who do not expect file-based input to be used implicitly.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/moltbot-bot-flow.mjs:9

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/moltbot-human-flow.mjs:8

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/paytrigo.mjs:8