Back to skill

Security audit

πŸ¦„ Powerloom Uniswap V3 timeseries data

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real Powerloom/Uniswap monitoring skill, but its optional wallet-funded setup asks for raw wallet and service credentials and can sign on-chain payments, so it needs careful review before install.

Prefer the free-key/browser onboarding path. Do not paste a primary wallet private key into chat; if using wallet-funded signup or top-up, use a burner wallet with only the needed funds, review recipient/amount/chain before --yes, and remove POWERLOOM_EVM_PRIVATE_KEY afterward. Store API and Telegram secrets in a proper secret store rather than long-lived cron text where possible.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 Β· Insecure Skill Coding Practices

Warning
Location
references/08-openclaw-one-shot.md:13
Finding

Sensitive credentials are collected through chat and unnecessarily persisted in configuration and cron definitions

Content
View full analysis

Vulnerability Details

File Location: references/08-openclaw-one-shot.md:13-17, 36-37, 52-60; references/09-openclaw-one-shot-free-key.md:15-25, 31-33, 50-60
Vulnerability Type: Plaintext sensitive credential handling and excessive secret persistence
Risk Level: Medium

Complete Vulnerable Snippets

From references/08-openclaw-one-shot.md:13-17:

text
a. **Payer wallet private key** β€” paste your EVM private key for the funded wallet that will pay 50 $POWER for the credit plan. **Use a burner wallet only** β€” never a wallet holding significant assets or with extensive transaction history. This key is consumed by `node scripts/signup-pay.mjs` and stored in OpenClaw env as `POWERLOOM_EVM_PRIVATE_KEY`.

b. **Telegram alerts** β€” ask explicitly: "Do you want Telegram alerts for whale swaps? If yes, paste your `POWERLOOM_TELEGRAM_BOT_TOKEN` and `POWERLOOM_TELEGRAM_CHAT_ID`. If no, type 'skip' and alerts will print to stdout only."

From references/08-openclaw-one-shot.md:36-37:

text
3. After signup, set the `sk_live_...` API key and all six env vars in OpenClaw under
   `skills.entries.powerloom-bds-univ3.env.*`:
   `POWERLOOM_EVM_PRIVATE_KEY` (from input a), `POWERLOOM_EVM_RPC_URL`, `POWERLOOM_EVM_CHAIN_ID`, `POWERLOOM_PLAN_ID`, `POWERLOOM_TOKEN_SYMBOL`, `POWERLOOM_API_KEY` (from `signup-pay.mjs` claim output).

From references/08-openclaw-one-shot.md:52-60:

text
- Message: a shell command that `cd`s to the skill dir, sets env inline, then runs `node scripts/whale-cron.mjs`. Required env in the cron message:
  - `POWERLOOM_API_KEY=<value from signup-pay.mjs claim output>`
  - `POWERLOOM_BDS_MCP_CALL_TIMEOUT_MS=120000`
  - `WHALE_CRON_THRESHOLD=10000` (default; only override if I asked for a different threshold)
- Telegram env in the cron message β€” **only** if input (b) yielded both values:
  - `POWERLOOM_TELEGRAM_BOT_TOKEN=<value from input (b)>`
  - `POWERLOOM_TELEGRAM_CHAT_ID=<value from input (b)>`

From `reference ...[truncated 4488 chars]

Remediation
View remediation

Remediation Suggestions

  1. Do not request raw private keys through chat.

    • Use a hardware wallet, external signer, WalletConnect-style approval, or an encrypted keystore with an interactive password.
    • Have the user execute the payment command locally when a secure external signer cannot be integrated.
  2. Do not persist the wallet private key in Skill configuration.

    • Supply it only to the single payment process through a protected secret channel.
    • Remove it immediately after the transaction completes.
    • Ensure recurring monitoring jobs cannot read wallet credentials.
  3. Use a secret manager for recurring credentials.

    • Store Powerloom and Telegram credentials in a platform-supported encrypted secret store.
    • Have cron jobs reference secret identifiers or securely injected environment variables rather than embedding literal values in cron command text.
  4. Minimize exposure in agent context and logs.

    • Never repeat secrets in summaries, tool output, exception messages, or generated shell commands.
    • Add automatic redaction for sk_live_*, EVM private-key patterns, Telegram bot tokens, and configured secret values.
  5. Apply least privilege and lifecycle controls.

    • Use a dedicated burner wallet with only the exact required funds.
    • Rotate API and Telegram credentials after suspected disclosure.
    • Document deletion and rotation steps after wallet-funded onboarding.
  6. Harden configuration storage.

    • Restrict configuration and scheduler-definition permissions to the service account.
    • Exclude secret-bearing files from backups and diagnostic bundles, or encrypt them using separately managed keys.
    • Prevent administrative interfaces from rendering literal secret values.
  7. Revise both one-shot runbooks.

    • Replace instructions to paste credentials into chat with secure secret-entry procedures.
    • Remove the instruction to retain POWERLOOM_EVM_PRIVATE_KEY after signup.
    • Replace i ...[truncated 56 chars]
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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (34)

YARA rule 'agent_skill_credential_exfiltration_webhook': AI agent skill credential harvesting followed by webhook or external exfiltration [agent_skills]

Critical
Category
YARA Match
Confidence
85% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt Β· scripts/whale-cron.mjs (reported line 15)May include surrounding context.

js
from "path";
import { callTool } from "./lib/mcp.mjs";
import { defaultMcpCallTimeoutIfUnset, telegramBotToken, telegramChatId } from "./lib/powerloom-env.mjs";
import { loadState, saveState, fingerprintTrade, rememberFingerprint, wasEmitted } from "./lib/state.mjs";
import { flattenAllTradesFromSnapshot, tradeUsd, tradeDirectionLabel } from "./lib/trade-utils.mjs";

const THRESHOLD = parseFloat(process.env.WHALE_CRON_THRESHOLD || "10000");
const MAX_LOOPS = parseInt(process.env.WHALE_CRON_MAX_LOOPS || "10", 10);
const STATE_FILE = process.env.WHALE_CRON_STATE_FILE || ".powerloom/whale-cron-state.json";
const POOL_CACHE_FILE = process.env.WHALE_CRON_POOL_CACHE || ".powerloom/pool-metadata-cache.json";
defaultMcpCallTimeoutIfUnset(120000);

const TG_TOKEN = telegramBotToken();
const TG_CHAT = telegramChatId();

// ─── Pool metadata cache ───

function loadPoolCache() {
  try {
    if (existsSync(POOL_CACHE_FILE)) return JSON.parse(readFileSync(POOL_CACHE_FILE, "utf8"));
  }

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
_snapshot_trades_pool_address` per pool) or `bds_mpp_snapshot_allTrades` via **`whale-cron.mjs`** |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
_snapshot_trades_pool_address` per pool) or `bds_mpp_snapshot_allTrades` via **`whale-cron.mjs`** |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
_snapshot_trades_pool_address` per pool) or `bds_mpp_snapshot_allTrades` via **`whale-cron.mjs`** |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
_snapshot_trades_pool_address` per pool) or `bds_mpp_snapshot_allTrades` via **`whale-cron.mjs`** |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
_snapshot_trades_pool_address` per pool) or `bds_mpp_snapshot_allTrades` via **`whale-cron.mjs`** |

Known Vulnerable Dependency: ws==8.17.1 β€” 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
98% confidence
Finding

The lockfile pins transitive dependency ws to version 8.17.1, which the provided advisory data identifies as affected by an uninitialized memory disclosure and a memory-exhaustion denial of service. Because this skill performs autonomous monitoring and likely maintains websocket connections through ethers, a vulnerable ws package is plausibly reachable in normal operation and could expose process memory or allow remote service disruption.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt Β· references/06-troubleshooting.md (reported line 6)May include surrounding context.

md
| Symptom | Cause | Fix |
|---------|--------|-----|
| Pay-signup "recipient did not match" / wrong first tx (POWER 7869) | **`signup-pay.mjs` used ERC-20** while plan is **`payment_kind: native_value`** (CGT) | **Update** the script from the current skill repo, or use a flow that checks **`quote.payment_kind`**: native = `sendTransaction({ to, value })` only, not `token.transfer`. `credits-topup.mjs` already branches on `payment_kind`. |
| HTTP 401 | Bad or missing API key | Re-copy key from the metering dashboard ([bds-metering.powerloom.io/metering](https://bds-metering.powerloom.io/metering)) or your CLI profile; fix `POWERLOOM_API_KEY`. |
| HTTP 402 | Credits exhausted | Top up; reduce recipe cadence; run `ensure-credits.mjs` before crons. |
| HTTP 429 | Rate limit | Increase heartbeat interval; for **cron** schedules prefer **poll** (fewer parallel calls) instead of many snapshot fan-outs. |
| Tool timeout | Backlog / slow finalization | Raise `POWERLOOM_BDS_MCP_CALL_TIMEOUT_MS`; reduce snapshot scope (`max_events` / fewer pools). |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt Β· references/08-openclaw-one-shot.md (reported line 62)May include surrounding context.

md
- `POWERLOOM_TELEGRAM_CHAT_ID=<value from input (b)>`
   - Do NOT consult OpenClaw `channels.telegram`, `openclaw.json`, or any other config source for Telegram credentials β€” only use what I pasted in chat for input (b).

5. Before the first run: `rm -f .powerloom/whale-cron-state.json` if you need a clean epoch cursor.
   Keep `.powerloom/pool-metadata-cache.json` across reinstalls unless debugging metadata.

6. Set WHALE_CRON_STATE_FILE and WHALE_CRON_POOL_CACHE to paths outside the skill directory (e.g. in the workspace root) so they survive `openclaw skills install --force`.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt Β· references/09-openclaw-one-shot-free-key.md (reported line 62)May include surrounding context.

md
- `POWERLOOM_TELEGRAM_CHAT_ID=<value from input (b)>`
   - Do NOT consult OpenClaw `channels.telegram`, `openclaw.json`, or any other config source for Telegram credentials β€” only use what I pasted in chat for input (b).

5. Before the first run: `rm -f .powerloom/whale-cron-state.json` if you need a clean epoch cursor.
   Keep `.powerloom/pool-metadata-cache.json` across reinstalls unless debugging metadata.

6. Set WHALE_CRON_STATE_FILE and WHALE_CRON_POOL_CACHE to paths outside the skill directory (e.g. in the workspace root) so they survive `openclaw skills install --force`.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script requires a raw EVM private key and uses it to sign and submit blockchain transactions, granting the skill direct spending capability. In the context of a monitoring skill, this is dangerous because compromise, misuse, or operator misunderstanding can result in unauthorized asset transfers, and the amount/recipient are derived from service responses rather than a user-maintained local policy.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

This script can broadcast real on-chain native-token or ERC-20 payments based on remotely supplied plan metadata, which is materially beyond the advertised monitoring and analytics scope of the skill. Even with a confirmation prompt, embedding payment execution into a monitoring skill increases the chance that an operator supplies a funded private key and unintentionally authorizes value transfer to a service-controlled recipient.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

This script introduces payment and signup automation, including on-chain value transfer, into a skill described as a monitoring and analytics tool. That expands the trust boundary from read-only data access to active fund movement, creating a high-risk capability mismatch that could cause users or agents to spend funds unexpectedly if they enable the documented environment variables and confirmation bypasses.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The code accepts a raw private key from environment variables, constructs a wallet, fetches payment instructions from a remote service, and signs a native or ERC-20 transfer to a recipient returned in the quote. In the context of a monitoring skill, this is dangerous because compromise, misconfiguration, or abuse of the metering endpoint/RPC path can turn a read-oriented integration into an automated fund-spending mechanism, especially in non-interactive mode via --yes or POWERLOOM_SIGNUP_PAY_CONFIRM=yes.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

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.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill exposes capabilities that rely on environment variables and outbound network access, but it does not declare any explicit tool scope or allowed-tools boundary. In an agent host, this can cause the skill to run with broader privileges than intended, increasing the chance of unintended secret access or unreviewed external requests during execution.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The trigger list includes broad phrases such as "Powerloom," "verify on-chain," and "verified data," which can match ordinary user requests outside the intended Uniswap V3 monitoring context. Overbroad activation can cause the skill to engage unexpectedly, leading to unnecessary network calls, confusion, or accidental invocation of workflows that reference sensitive setup paths like API keys or wallet-funded onboarding.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The markdown tells users to place an API key in the environment and later set Telegram bot credentials, but it does not include any warning about keeping these secrets out of shell history, shared profiles, logs, or source control. Because these are credentials that affect privacy and account security, the quickstart should disclose the sensitivity of these values.

Content

No source excerpt is available for this finding.

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
80% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

Scanner excerpt Β· references/06-troubleshooting.md (reported line 16)May include surrounding context.

md
| Skill β€œready” in `skills list` / dashboard but main chat ignores it | **Install β‰  injection.** The chat agent may not attach every skill to every session; per-agent config, a **new** session after enabling the skill, or product limits on which skills the model sees. | Enable the skill for **that** agent; start a new chat; add **BDS MCP** in config if you need tools in the tool list. For deterministic behavior, run **`node scripts/…`**. |
| `OPENCLAW_WORKSPACE_DIR` seems wrong in Docker | Compose interpolates `${VAR}` from a **`.env` next to `docker-compose.yml`**, the shell **environment**, or an `env_file` the compose file references β€” whatever OpenClaw’s install template ships. | Set **`OPENCLAW_WORKSPACE_DIR=`** in that `.env` to the **host** absolute path for workspace (e.g. `/Users/you/.openclaw/workspace`). Run **`docker compose config`** to verify substitution; **recreate** containers after changing `.env` (`up -d` / `up --force-recreate` as needed). |
| `NO_SESSION` / β€œsession_id never arrived” | SSE bootstrap did not expose a parseable `session_id` (UUID vs hex, proxy, or stale client) | Confirm `POWERLOOM_MCP_URL` ends with `/sse` reachable from the runtime (e.g. Docker). Set **`POWERLOOM_BDS_MCP_DEBUG=1`** once to log the first bytes of the SSE stream in the error. |
| `ENOENT` on `.../skills/.../SKILL.md` (OpenClaw in Docker) | The **container** does not have that file at the path the process checks. Common: wrong **host** tree for **`OPENCLAW_WORKSPACE_DIR`** (compose often mounts `${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace` β€” skills belong under that dir’s `skills/` on the host, not a second guess at `~` if the env points elsewhere), nested slug folder, or symlink outside the mount. | **In the failing container:** `ls -la /home/node/.openclaw/workspace/skills/powerloom-bds-univ3/SKILL.md` (official compose) **or** `ls` under `/app/skills/...` if your error path uses `/app`. Copy/rsync the skill to the **host path** that maps to the show
...[truncated 25 chars]

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

Scanner excerpt Β· references/06-troubleshooting.md (reported line 16)May include surrounding context.

md
| Skill β€œready” in `skills list` / dashboard but main chat ignores it | **Install β‰  injection.** The chat agent may not attach every skill to every session; per-agent config, a **new** session after enabling the skill, or product limits on which skills the model sees. | Enable the skill for **that** agent; start a new chat; add **BDS MCP** in config if you need tools in the tool list. For deterministic behavior, run **`node scripts/…`**. |
| `OPENCLAW_WORKSPACE_DIR` seems wrong in Docker | Compose interpolates `${VAR}` from a **`.env` next to `docker-compose.yml`**, the shell **environment**, or an `env_file` the compose file references β€” whatever OpenClaw’s install template ships. | Set **`OPENCLAW_WORKSPACE_DIR=`** in that `.env` to the **host** absolute path for workspace (e.g. `/Users/you/.openclaw/workspace`). Run **`docker compose config`** to verify substitution; **recreate** containers after changing `.env` (`up -d` / `up --force-recreate` as needed). |
| `NO_SESSION` / β€œsession_id never arrived” | SSE bootstrap did not expose a parseable `session_id` (UUID vs hex, proxy, or stale client) | Confirm `POWERLOOM_MCP_URL` ends with `/sse` reachable from the runtime (e.g. Docker). Set **`POWERLOOM_BDS_MCP_DEBUG=1`** once to log the first bytes of the SSE stream in the error. |
| `ENOENT` on `.../skills/.../SKILL.md` (OpenClaw in Docker) | The **container** does not have that file at the path the process checks. Common: wrong **host** tree for **`OPENCLAW_WORKSPACE_DIR`** (compose often mounts `${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace` β€” skills belong under that dir’s `skills/` on the host, not a second guess at `~` if the env points elsewhere), nested slug folder, or symlink outside the mount. | **In the failing container:** `ls -la /home/node/.openclaw/workspace/skills/powerloom-bds-univ3/SKILL.md` (official compose) **or** `ls` under `/app/skills/...` if your error path uses `/app`. Copy/rsync the skill to the **host path** that maps to the show
...[truncated 25 chars]

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This markdown file defines user-intent trigger mappings, so SQP-1 applies. Phrases such as β€œWhale” and β€œOne pool” are underspecified and could overlap with many unrelated user requests, with no constraints or negative examples to clarify invocation scope.

Content

No source excerpt is available for this finding.

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 Β· scripts/lib/dispatch.mjs (reported line 22)May include surrounding context.

js
console.log(text);
      return;
    }
    const u = `https://api.telegram.org/bot${token}/sendMessage`;
    const r = await fetch(u, {
      method: "POST",
      headers: { "Content-Type": "application/json" },

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 Β· scripts/whale-cron.mjs (reported line 91)May include surrounding context.

js
console.log(text);
      return;
    }
    const u = `https://api.telegram.org/bot${token}/sendMessage`;
    const r = await fetch(u, {
      method: "POST",
      headers: { "Content-Type": "application/json" },

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 Β· scripts/whale-cron.mjs (reported line 100)May include surrounding context.

js
console.log(text);
      return;
    }
    const u = `https://api.telegram.org/bot${token}/sendMessage`;
    const r = await fetch(u, {
      method: "POST",
      headers: { "Content-Type": "application/json" },

Static analysis

No suspicious patterns detected.