Back to skill

Security audit

OpenCog

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its prediction-market trading purpose, but it handles real wallet keys and installation provenance in ways users should review carefully.

Install only from a repository and commit you trust, preferably one matching the declared homepage. Use a dedicated low-value wallet, verify ~/.openclaw/.env is owner-only readable, avoid storing a valuable mainnet key there, and treat mainnet commands and token approvals as real financial actions.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/setup.mjs:52
Finding
Generated Wallet Private Key Is Not Protected by Enforced File Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.mjs:52-55` **Vulnerability Type**: Plaintext credential storage with insecure default permissions **Risk Level**: High ### Vulnerable Code ```js const pk = generatePrivateKey(); const account = privateKeyToAccount(pk); _mkdirSync(_envDir, { recursive: true }); _appendFileSync(_envFile, `\nPRIVATE_KEY=${pk}\n`); ``` ### Technical Analysis The setup script generates a secp256k1 private key and stores it in plaintext at `~/.openclaw/.env`. Neither the directory nor the file is created with an explicit restrictive mode. When `appendFileSync` creates a file, its effective permissions ordinarily derive from a default mode such as `0666`, filtered through the process umask. Under a common `022` umask, the resulting file may be `0644`, making the wallet key readable by other local users. Likewise, `mkdirSync` does not explicitly require mode `0700`. This conflicts with the security guidance in `SKILL.md:55`, which advises users to apply `chmod 600`, but the setup routine does not enforce that protection. Because the same key may control real Base mainnet assets, reliance on the caller's umask is not an adequate security boundary. The use of `appendFileSync` also lacks explicit checks against a pre-existing symbolic link. If an attacker who can manipulate the target path prepares an appropriate symlink, the secret may be written to an unintended file. Practical exploitation depends on the attacker's existing filesystem access and ownership constraints. ### Attack Path 1. A user runs: ```bash node scripts/setup.mjs --generate ``` 2. The script creates `~/.openclaw/.env` using permissions inherited from the runtime environment and current umask. 3. Under a permissive or typical configuration, another local account or process reads the file. 4. The attacker extracts the `PRIVATE_KEY` value. 5. The attacker imports the key into a wallet and signs arbitrary transactions. 6. Any toke ...[truncated 1126 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the wallet directory with owner-only access: ```js mkdirSync(envDir, { recursive: true, mode: 0o700 }); chmodSync(envDir, 0o700); ``` 2. Create the key file atomically with exclusive, owner-only permissions rather than using `appendFileSync`: ```js const fd = openSync(envFile, "wx", 0o600); try { writeFileSync(fd, `PRIVATE_KEY=${pk}\n`, { encoding: "utf8" }); } finally { closeSync(fd); } ``` 3. If an existing `.env` file must be supported, inspect it using `lstatSync`, reject symbolic links and non-regular files, verify that it is owned by the current user, and set its mode to `0600` before writing. 4. Avoid storing the key in a shared configuration file. Prefer a dedicated wallet file with a narrowly scoped parser, an encrypted keystore protected by a user-supplied password, or an operating-system credential store. 5. Verify permissions after creation and fail closed if the directory or file remains accessible to group or other users. 6. Continue to avoid printing or transmitting the raw key, and retain the recommendation to use a dedicated low-value wallet. ]]>

T08 · Insecure Dependencies

Warning
Location
README.md:17
Finding
Installation Instructions Reference an Unpinned Repository That Differs from the Declared Homepage<![CDATA[ ## Vulnerability Details **File Location**: `README.md:17` **Related Location**: `SKILL.md:4` **Vulnerability Type**: Mutable and inconsistent supply-chain installation source **Risk Level**: Medium ### Vulnerable Code The installation instructions specify: ```bash git clone https://github.com/0xAstraea/opencog-basic precog ``` However, the Skill metadata declares a different repository: ```yaml homepage: "https://github.com/openclaw/precog-skill" ``` ### Technical Analysis The documented installation process clones the current default branch of `0xAstraea/opencog-basic` without pinning a commit, release tag, or verified artifact digest. This repository owner and project name differ from the repository declared as the Skill homepage. Consequently, users following the README may execute code that is different from the audited artifact. The effective payload can change whenever the remote default branch changes. This is especially significant because the installed scripts are expected to read `~/.openclaw/.env`, access a wallet private key, sign transactions, and submit token approvals and trades. The committed `package-lock.json` provides integrity metadata for npm packages, but it does not authenticate the Git repository or guarantee that the cloned Skill source matches the reviewed version. The README also directs users to run `npm install`, rather than a frozen installation such as `npm ci`. No evidence was found that the currently referenced repository is malicious. The vulnerability is the lack of source identity consistency and immutable version pinning, which creates a preventable supply-chain trust gap. ### Attack Path 1. A user trusts the audited Skill or its declared `openclaw/precog-skill` homepage. 2. The user follows `README.md` and clones the different `0xAstraea/opencog-basic` repository. 3. The fetched default branch contains code that has changed since the audit, whether through account compromise, malicious maintenance, ...[truncated 1326 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Select one canonical repository and make the README installation URL match the homepage and package metadata. 2. Pin installations to an immutable, reviewed commit: ```bash git clone https://github.com/openclaw/precog-skill precog cd precog git checkout --detach <reviewed-commit-sha> ``` 3. Publish signed release tags and provide SHA-256 checksums or cryptographic attestations for release artifacts. 4. Document the exact audited version or commit in `SKILL.md`, `README.md`, and `package.json`. 5. Use: ```bash npm ci ``` instead of `npm install` for reproducible dependency installation from the committed lockfile. 6. Add automated release checks that fail if the documented repository identity, package identity, and declared homepage diverge. 7. Encourage users to verify the checked-out commit and release signature before exposing a wallet key to the installed code. ]]>
Vulnerability Patterns
  • 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
  • Rogue AgentSelf-Modification, Session Persistence
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (33)

Known Vulnerable Dependency: vitest==1.6.1 — 1 advisory(ies): CVE-2026-47429 (When Vitest UI server is listening, arbitrary file can be read and executed)

Critical
Category
Supply Chain
Confidence
90% confidence
Finding
Vitest 1.6.1 is flagged for arbitrary file read and execution when the Vitest UI server is listening. This is a real issue, but it affects test/UI-server usage rather than the production runtime of the trading skill; still, in a wallet- or market-related project, compromise of a developer environment could expose secrets, test keys, or source code.

Known Vulnerable Dependency: vitest==1.6.1 — 1 advisory(ies): CVE-2026-47429 (When Vitest UI server is listening, arbitrary file can be read and executed)

Critical
Category
Supply Chain
Confidence
95% confidence
Finding
If the project resolves to vitest 1.6.1, the cited advisory indicates that the Vitest UI server can allow arbitrary file read and code execution. Even though vitest is a devDependency, exploitation in a developer workstation or CI runner could expose the plaintext wallet key described by this skill and potentially compromise signing credentials or build infrastructure.

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Content
---
name: precog
description: "Trade on prediction markets. Create a local wallet, list markets, check prices, buy and sell outcome shares. Coming soon: create and fund markets directly from this skill."
homepage: "https://github.com/openclaw/precog-skill"
env:
  PRIVATE_KEY:
    description: "Secp256k1 private key (0x-prefixed) for signing transactions. Generated locally by running setup.mjs --generate and saved to ~/.openclaw/.env. Never transmitted over the network."
    required: true
  PRECOG_RPC_URL:
    description: "Override the default public RPC endpoints (https://sepolia.base.org for testnet,
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The ABI includes broad administrative role-management functions such as addAdmin, grantRole, revokeRole, addCaller, and addMarketOperator that are not justified by a simple trading skill. If an agent or integration can access these methods, it could escalate privileges, alter trusted operators, change allowed assets/oracles/receivers, or permanently compromise control of markets and funds.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The ABI exposes ownedTokenMint, ownedTokenBurn, ownedTokenMove, and ownedTokenTransferOwnership, which are highly privileged token-control operations unrelated to ordinary prediction-market trading. In the context of a skill that can create a local wallet and trade on behalf of users, these functions are especially dangerous because they could enable arbitrary balance manipulation, confiscation, issuance, or transfer of token ownership if misused or surfaced by mistake.

Known Vulnerable Dependency: nanoid==3.3.11 — 3 advisory(ies): CVE-2026-67214 (nanoid: non-secure generators can loop indefinitely with negative size); CVE-2026-67213 (nanoid: custom generators can loop indefinitely when size is zero); CVE-2026-73086 (nanoid: Integer Overflow or Wraparound)

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Known Vulnerable Dependency: postcss==8.5.8 — 4 advisory(ies): CVE-2026-45623 (PostCSS: Arbitrary file read and information disclosure via attacker-controlled ); CVE-2026-69153 (PostCSS: incomplete fix of GHSA-6g55-p6wh-862q — attacker-controlled sourceMappi); CVE-2026-41305 (PostCSS has XSS via Unescaped </style> in its CSS Stringify Output) +1 more

High
Category
Supply Chain
Confidence
80% confidence
Finding
PostCSS 8.5.8 is present and has multiple advisories involving file read, incomplete source map fixes, and output encoding/XSS issues. In this skill it is a transitive dev dependency used by Vite, so the risk is more relevant to development/build environments and any workflow that processes attacker-supplied CSS or source maps.

Known Vulnerable Dependency: vite==5.4.21 — 3 advisory(ies): CVE-2026-39365 (Vite Vulnerable to Path Traversal in Optimized Deps `.map` Handling); CVE-2026-53571 (vite: `server.fs.deny` bypass on Windows alternate paths); CVE-2026-53632 (launch-editor: NTLMv2 hash disclosure via UNC path handling on Windows)

High
Category
Supply Chain
Confidence
86% confidence
Finding
Vite 5.4.21 is flagged for path traversal and Windows path handling issues, including file access bypasses and possible NTLM hash disclosure. Although it is a dev dependency, these are genuine vulnerabilities that can matter if developers run Vite or related tooling on untrusted networks or with attacker-influenced paths/files.

Known Vulnerable Dependency: ws==8.18.3 — 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
80% confidence
Finding
The ws 8.18.3 package is flagged for memory disclosure and memory exhaustion issues. Because ws is a runtime dependency of viem, this is more relevant than purely dev-only findings: if the skill uses WebSocket RPC connections to blockchain nodes or accepts hostile peer traffic, exploitation could cause denial of service or unintended data exposure.

Credential Access

High
Category
Privilege Escalation
Content
"PRECOG_NETWORK": "optional — default network: 'sepolia' (testnet, default) or 'mainnet' (Base mainnet, real funds). Can be overridden per-command with --network."
    },
    "configPaths": {
      "~/.openclaw/.env": "created by setup.mjs --generate. Stores PRIVATE_KEY in plaintext. Treat as a wallet key file: restrict permissions and back it up."
    },
    "networks": {
      "sepolia": { "chainId": 84532, "contract": "0x61ec71F1Fd37ecc20d695E83F3D68e82bEfe8443" },
Confidence
83% confidence
Finding
The skill explicitly specifies that ~/.openclaw/.env stores a blockchain PRIVATE_KEY in plaintext. For a trading skill that can operate on mainnet with real funds, plaintext wallet-key storage materially increases the chance of wallet compromise through local malware, accidental backup/sync exposure, or overly permissive filesystem access.

Credential Access

High
Category
Privilege Escalation
Content
// ── Load ~/.openclaw/.env ─────────────────────────────────────────────────────

const ENV_FILE = join(homedir(), ".openclaw", ".env");
if (existsSync(ENV_FILE)) {
  for (const line of readFileSync(ENV_FILE, "utf8").split("\n")) {
    const m = line.match(/^([A-Z_][A-Z0-9_]*)=(.+)$/);
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
// ── Load ~/.openclaw/.env ─────────────────────────────────────────────────────

const ENV_FILE = join(homedir(), ".openclaw", ".env");
if (existsSync(ENV_FILE)) {
  for (const line of readFileSync(ENV_FILE, "utf8").split("\n")) {
    const m = line.match(/^([A-Z_][A-Z0-9_]*)=(.+)$/);
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
// ── Load ~/.openclaw/.env ─────────────────────────────────────────────────────

const ENV_FILE = join(homedir(), ".openclaw", ".env");
if (existsSync(ENV_FILE)) {
  for (const line of readFileSync(ENV_FILE, "utf8").split("\n")) {
    const m = line.match(/^([A-Z_][A-Z0-9_]*)=(.+)$/);
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
// ── Load ~/.openclaw/.env ─────────────────────────────────────────────────────

const ENV_FILE = join(homedir(), ".openclaw", ".env");
if (existsSync(ENV_FILE)) {
  for (const line of readFileSync(ENV_FILE, "utf8").split("\n")) {
    const m = line.match(/^([A-Z_][A-Z0-9_]*)=(.+)$/);
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
//
// Usage:
//   node setup.mjs              # check wallet status, show address + balances
//   node setup.mjs --generate   # generate a new wallet, save to ~/.openclaw/.env
//
// Env: PRECOG_RPC_URL (optional)
import { existsSync, readFileSync, appendFileSync, mkdirSync } from "fs";
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
//
// Usage:
//   node setup.mjs              # check wallet status, show address + balances
//   node setup.mjs --generate   # generate a new wallet, save to ~/.openclaw/.env
//
// Env: PRECOG_RPC_URL (optional)
import { existsSync, readFileSync, appendFileSync, mkdirSync } from "fs";
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
//
// Usage:
//   node setup.mjs              # check wallet status, show address + balances
//   node setup.mjs --generate   # generate a new wallet, save to ~/.openclaw/.env
//
// Env: PRECOG_RPC_URL (optional)
import { existsSync, readFileSync, appendFileSync, mkdirSync } from "fs";
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
//
// Usage:
//   node setup.mjs              # check wallet status, show address + balances
//   node setup.mjs --generate   # generate a new wallet, save to ~/.openclaw/.env
//
// Env: PRECOG_RPC_URL (optional)
import { existsSync, readFileSync, appendFileSync, mkdirSync } from "fs";
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
const existingKey = _getPrivateKey();
    if (existingKey) {
      console.error(`Wallet already set: ${privateKeyToAccount(existingKey).address}`);
      console.error("Remove PRIVATE_KEY from ~/.openclaw/.env first.");
      return { error: "already_exists" };
    }
    if (_existsSync(_envFile) && _readFileSync(_envFile, "utf8").includes("PRIVATE_KEY=")) {
Confidence
89% confidence
Finding
The script checks for and manages a PRIVATE_KEY stored in ~/.openclaw/.env, indicating reliance on plaintext local secret storage for a cryptocurrency wallet. If the file is readable by other local users, backups, malware, or logs, compromise of the private key would let an attacker fully control the wallet and steal funds. In this skill context, handling prediction-market trading makes wallet compromise especially sensitive because the key authorizes financial transactions.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The skill instructs users to validate they are human by using a passport-based identity system and says identity is kept private, but it does not provide a meaningful privacy warning about sharing identity-derived data with a third-party verifier. In a wallet/trading context, this can cause users to underestimate privacy, compliance, and data-handling risks, especially because identity workflows are high-sensitivity and often involve irreversible disclosure or correlation risks.

Lp3

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding
The skill declares environment variable requirements, including a private key, but does not declare an explicit tool/permission scope. In an agent setting, missing scope metadata weakens least-privilege boundaries and can let the runtime expose sensitive capabilities more broadly than intended.

Session Persistence

Medium
Category
Rogue Agent
Content
---
name: precog
description: "Trade on prediction markets. Create a local wallet, list markets, check prices, buy and sell outcome shares. Coming soon: create and fund markets directly from this skill."
homepage: "https://github.com/openclaw/precog-skill"
env:
  PRIVATE_KEY:
Confidence
95% confidence
Finding
The skill is explicitly designed to create and persist a local wallet private key in `~/.openclaw/.env` in plaintext across sessions. Persistent storage of signing keys materially increases compromise impact: any local process, backup leak, or misconfigured permissions can lead to theft of funds or unauthorized market actions.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
## Security and local state

- **`~/.openclaw/.env`** — created by `setup.mjs --generate`. Stores `PRIVATE_KEY` in plaintext. Treat it like a wallet key file: restrict permissions (`chmod 600`) and back it up. Losing it means losing access to any funds in that wallet.
- **No key is ever transmitted.** Transactions are signed locally; only the signed transaction is broadcast to the RPC.
- **Use a throwaway wallet.** The MATE markets use a practice token with no real value — ideal for testing. Do not load a high-value key into this skill.
- **Custom RPC risk.** If you set `PRECOG_RPC_URL`, use only a trusted endpoint. An untrusted RPC can observe signed transaction contents (but cannot extract your private key from them).
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Session Persistence

Medium
Category
Rogue Agent
Content
→ node sell.mjs --market 4 --outcome 1 --shares <n> --min <suggested-min>
→ After trade: suggest checking positions or remaining balance

User: "Create a market about X" / "Can you create a market for Y?"
→ Tell the user to go to https://core.precog.markets/84532/create-market
→ Explain briefly: log in with MetaMask, fill the form, submit for review
→ Remind them: after submission they need to fund the market at the launchpad
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The manifest states market creation is 'coming soon', yet the ABI already exposes createMarket and createCustomMarket. This mismatch is dangerous because users and calling agents may trust the narrower description and unknowingly invoke market-creation flows that can commit funds, create on-chain liabilities, or interact with unreviewed code paths outside the advertised scope.

Static analysis

No suspicious patterns detected.