Back to skill

Security audit

Liquid Agent stocks

Security checks for vulnerabilities and agentic risk

Overview

This skill is transparent about using a trading API, but it asks agents to sign wallet authorizations and server-generated blockchain transactions without enough validation or payment controls.

Review this skill carefully before installing. Use it only with a wallet you are comfortable using for experimental on-chain trading, verify every transaction and permit in your wallet, avoid gasless EIP-7702 signing unless you understand the delegation, and require explicit approval before any paid x402 retry or irreversible send/redeem action.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:43
Finding

Blind Signing of Server-Generated Financial Transactions

Content
View full analysis
`. If `vaultCount > 0`, use `vaults[0].vault` and **skip step 4**. Creating a second vault is almost never what the user wants. 4. **Create your vault (once)** — `POST /v1/create-vault` body `{}` → `{to,data,value,chainId}`. Sign, broadcast, wait for the receipt, then re-run step 3 to get the vault address. 5. **Custom weights (optional)** — `POST /v1/set-weights` body `{"vault":"0x…","weightsBps":[4000,2000,2000,2000]}` → unsigned tx. Order is NVDA, META, AAPL, GOOGL. Each weight can move at most 2000 bps per call. Default is 2500 each. 6. **Buy** — two calls, one on-chain transaction: - `POST /v1/buy` body `{"vault":"0x…","usdc":"2000000","permit":true,"owner":"0xYourAddress"}` → `{typedData}`. - Sign `typedData` off-chain with `eth_signTypedData_v4` (free, no gas). - `POST /v1/buy` again with `{"vault":"0x…","usdc":"2000000","permit":{"deadline":,"signature":"0x…"}}` → ONE unsigned `depositWithPermit` tx. Sign and broadcast with gas limit ~3,000,000. - No `approve` step is needed. Omit `permit` entirely only if your wallet cannot sign typed data; then you get `{steps:[approve, deposit]}` to send in order. 7. **Check it** — `GET /v1/vault/` → `navUsdc`, current vs target `weightsBps`, `rebalanceNeeded`. 8. **Rebalance (optional)** — `POST /v1/rebalance` body `{"vault":"0x…"}` → unsigned tx. Only when `rebalanceNeeded` is true or after changing weights. 9. **Sell / cash out** — `POST /v1/redeem` body `{"vault":"0x…","shares":"","inKind":false}` → unsigned tx that burns shares and pays USDC. `inKind:true` returns the raw stock tokens instead and works even if pricing is unavailable. `shares` comes from step 3. 10. **Send / gift (optional)** — `POST /v1/send` b ...[truncated 2067 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
SKILL.md:31
Finding

Insufficiently Validated EIP-7702 Authorization Workflow

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:46
Finding

Permit Signature Requested Without Mandatory Domain and Spender Validation

Content
View full analysis
,"signature":"0x…"}}` → ONE unsigned `depositWithPermit` tx. Sign and broadcast with gas limit ~3,000,000. - No `approve` step is needed. Omit `permit` entirely only if your wallet cannot sign typed data; then you get `{steps:[approve, deposit]}` to send in order. ``` ### Technical Analysis The API constructs the EIP-712 typed data that the wallet signs. The instructions do not require checking the EIP-712 domain, verifying contract, chain ID, owner, spender, token amount, nonce, or deadline. A permit signature can authorize token spending without a separate on-chain approval transaction. If the API returns altered typed data, the resulting signature may authorize a different spender, excessive amount, or unexpectedly long validity period. Merely copying the deadline from the API response does not establish that the signed authorization matches the user's intended purchase. ### Attack Path 1. The API or its delivery infrastructure is compromised. 2. The `/v1/buy` response contains typed data with an attacker-controlled spender, excessive amount, unexpected verifying contract, or extended deadline. 3. The agent asks the wallet to sign the typed data without decoding and validating every field. 4. The signature is delivered to the remote API. 5. The attacker submits the permit and uses the resulting allowance to transfer the authorized USDC. ### Impact Assessment An attacker could obtain an unintended USDC allowance from th ...[truncated 240 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
SKILL.md:74
Finding

Automatic Paid Request Guidance Lacks Payment Authorization Controls

Content
View full analysis
` for your drift. - `POST /v1/publish` body `{"vault":"0x…","label":"Alice's stocks"}` — **$0.25** flat. Mints a live shareable portfolio page at `https://api.liquidagent.ai/v/` for 24 hours; the user opens `viewUrl` with no wallet or login. Re-publish to keep it alive. ``` ### Technical Analysis The Skill tells payment-capable runtimes to retry HTTP 402 responses with payment. It does not require explicit user confirmation for each charge, validate the payment recipient and network, impose per-request or session spending limits, or prevent repeated payment retries. The purchase workflow separately requires confirmation of the investment amount, but that rule does not explicitly cover these optional API charges. Automated handling of payment challenges can therefore create unintended expenditures. ### Attack Path 1. A user or automated workflow invokes an optional paid endpoint. 2. The endpoint returns an x402 payment challenge. 3. A payment-capable runtime interprets “just retry with payment” as authorization to pay automatically. 4. A malicious, modified, or repeatedly returned challenge causes one or more USDC payments. 5. The charges occur without transaction-specific user approval or an enforced spending cap. ### Impact Assessment The direct impact is unintende ...[truncated 238 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The invocation phrases are broad enough to trigger on generic investing requests, which can cause an agent to engage a high-risk financial transaction skill in contexts where the user did not explicitly ask for on-chain tokenized stock trading. In a skill that can create unsigned blockchain transactions and initiate paid API flows, overbroad routing increases the chance of unintended financial actions or unsafe delegation.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 65)May include surrounding context.

md
ME=0xYourAddress
VAULT=$(curl -s $API/v1/balance/$ME | jq -r '.vaults[0].vault')
# 1) get the permit to sign
curl -s -X POST $API/v1/buy -H 'content-type: application/json' \
  -d "{\"vault\":\"$VAULT\",\"usdc\":\"5000000\",\"permit\":true,\"owner\":\"$ME\"}" > permit.json
# 2) sign permit.json .typedData with eth_signTypedData_v4 -> SIG, read DEADLINE from .typedData.message.deadline
# 3) get the single deposit tx

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 79)May include surrounding context.

md
These return HTTP 402 with an x402 v2 challenge. If your runtime can pay x402 (agentcash, an x402 fetch wrapper, or the OpenClaw x402 skill), just retry with payment. Everything above stays free.

- `GET /v1/signals` — **$0.04**. The whole basket's rebalancing signal in one call: per-stock returns, volatility, RSI, trend, relative strength, correlation, and an inverse-volatility `suggestedWeightsBps` you can pass straight to `/v1/set-weights`. Add `?vault=<yours>` for your drift.
- `POST /v1/publish` body `{"vault":"0x…","label":"Alice's stocks"}` — **$0.25** flat. Mints a live shareable portfolio page at `https://api.liquidagent.ai/v/<slug>` for 24 hours; the user opens `viewUrl` with no wallet or login. Re-publish to keep it alive.

## Rules

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 90)May include surrounding context.

md
These return HTTP 402 with an x402 v2 challenge. If your runtime can pay x402 (agentcash, an x402 fetch wrapper, or the OpenClaw x402 skill), just retry with payment. Everything above stays free.

- `GET /v1/signals` — **$0.04**. The whole basket's rebalancing signal in one call: per-stock returns, volatility, RSI, trend, relative strength, correlation, and an inverse-volatility `suggestedWeightsBps` you can pass straight to `/v1/set-weights`. Add `?vault=<yours>` for your drift.
- `POST /v1/publish` body `{"vault":"0x…","label":"Alice's stocks"}` — **$0.25** flat. Mints a live shareable portfolio page at `https://api.liquidagent.ai/v/<slug>` for 24 hours; the user opens `viewUrl` with no wallet or login. Re-publish to keep it alive.

## Rules

Static analysis

No suspicious patterns detected.