Is max-clinch/soho-pay safe?

https://github.com/openclaw/skills/tree/main/skills/max-clinch/soho-pay

86
SAFE

SOHO Pay is a well-architected EIP-712 payment skill with a thoughtful security model: it separates key custody from the credit layer, enforces mainnet confirmation gates, validates checksummed EVM addresses, and declares manual-only invocation. No prompt injection, hidden instructions, malicious code, or active data exfiltration was detected. The primary residual risks are structural to the skill's purpose: it handles real on-chain financial transactions, the address substitution attack surface is real for agent-mediated payments, and the autonomous invocation guard is an advisory env-var check rather than an enforced boundary.

Category Scores

Prompt Injection 93/100 · 30%
Data Exfiltration 82/100 · 25%
Code Execution 88/100 · 20%
Clone Behavior 88/100 · 10%
Canary Integrity 80/100 · 10%
Behavioral Reasoning 68/100 · 5%

Findings (8)

MEDIUM Address substitution attack surface in financial transactions -20

The merchantAddress parameter is accepted as a plain string argument and validated only for EVM checksum correctness. An AI agent acting as intermediary could be manipulated (via prompt injection upstream, social engineering, or confused deputy attacks) to pass an attacker-controlled address that passes all validation. There is no whitelist, name-to-address confirmation flow, or out-of-band verification.

MEDIUM Autonomous invocation guard is bypassable via environment variable manipulation -12

The autonomy guard in scripts/pay.js checks process.env.SOHO_AUTONOMOUS === 'true'. Any agent or process with the ability to set or unset environment variables prior to invocation can bypass this guard entirely. The protection is advisory metadata, not an enforced security boundary.

LOW dotenv loads .env from runtime CWD, expanding sensitive context into process.env -8

src/signer/config.js calls require('dotenv').config() with no explicit path argument, which loads .env from the process current working directory. If the skill is invoked from a directory containing a pre-existing .env file (e.g., a project root with DB credentials, API keys), those values enter process.env and are accessible to all code in the process, including error serializers and any future added logging.

LOW Raw private key in environment variable for LOCAL_PRIVATE_KEY mode -10

When SIGNER_PROVIDER=LOCAL_PRIVATE_KEY, the skill expects SOHO_DEV_PRIVATE_KEY to contain a raw hex private key. Environment variables are visible to all processes with the same UID, appear in /proc//environ, and may be captured in error reports or debug logs. The skill acknowledges this as dev-only, but the risk exists wherever this mode is used.

LOW Lock file ships with unrelated skill dependency reference -7

.clawhub/lock.json is committed with the skill and declares academic-research-hub v0.1.0 as an installed skill. While the Oathe installer only copies files and does not process this lock file as a dependency manifest, publishing another skill's reference inside a payment skill's repository is unexpected and could cause confusion about the skill's actual dependencies.

LOW Version inconsistency across metadata files -5

_meta.json declares version 2.0.0, skill.json declares 1.1.0, and package.json declares 1.0.0. This indicates loose release governance and makes it difficult to confirm which version of the skill is actually installed, complicating audit trails for financial operations.

INFO Canary files accessed post-install but confirmed intact -20

auditd PATH records show accesses to .env, .ssh/id_rsa, .aws/credentials, .npmrc, .docker/config.json, and gcloud credentials after skill installation (audit seq 6932-6937, ts 1771953487). The Canary Integrity check confirmed all files were unmodified. The accesses are consistent with the Oathe audit system performing its final integrity sweep and with npm reading .npmrc during package install.

INFO Manual invocation and confirmation requirements correctly declared 0

SKILL.md frontmatter declares invocation:manual and require_confirmation:true. skill.json mirrors these settings. The runtime guard in scripts/pay.js checks SOHO_AUTONOMOUS. The architecture documentation and threat model are thorough and reflect genuine security thinking. These controls are appropriate for a financial transaction skill.