Back to skill

Security audit

Opinion Skill

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real Opinion trading helper, but it asks users to run mutable remote code and handle private-key trading in ways that need Review before installation.

Install only if you are comfortable reviewing and pinning the external repository, replacing curl-to-bash with a verified Bun install, using a non-root working directory, and protecting the .env private key. Do not fund or approve a wallet you cannot afford to risk, and be aware that some market and position queries use an unencrypted HTTP API that can expose or alter decision-critical data.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
Findings (5)

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:24
Finding
Unverified Remote Bun Installer Is Piped Directly into a Shell<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:24-27` **Vulnerability Type**: Remote payload retrieval and immediate execution **Risk Level**: Critical ### Complete Code Snippet ```bash 1. 安装 bun: ```bash command -v bun >/dev/null 2>&1 && echo "bun $(bun --version)" || { curl -fsSL https://bun.sh/install | bash && source ~/.bashrc; } ``` ``` ### Technical Analysis The installation instruction retrieves a mutable script from `https://bun.sh/install` and pipes it directly into `bash`. The response is executed before the user can inspect it, and the command does not pin an installer version or validate a checksum or cryptographic signature. Although installing Bun is related to the declared functionality, executing an unverified remote response is not the minimum privilege or safest mechanism necessary to install the runtime. The effective code executed on the machine can change after the Skill has been reviewed. The risk applies even when the current endpoint is legitimate: compromise of the hosting service, distribution infrastructure, DNS or TLS trust chain, or installer publishing account could turn this command into arbitrary code execution. ### Attack Path 1. A user follows the documented prerequisite instructions. 2. Bun is not already installed, causing the fallback branch to run. 3. `curl` downloads the current response from `bun.sh`. 4. The response is passed directly to `bash` without integrity verification. 5. A compromised or malicious response executes with the privileges of the user running the command. 6. The payload can inspect files, access environment variables, modify the host, or steal wallet credentials subsequently stored on the system. ### Impact Assessment The remote payload obtains arbitrary command execution with the invoking user's privileges. Because the documentation consistently uses `/root/opinionskills`, execution as root is plausible. In that case, the payload could obtain full system control, ...[truncated 136 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the `curl | bash` installation workflow. - Pin a specific reviewed Bun release rather than using a mutable installer endpoint. - Download the release artifact as a separate step. - Verify its publisher-provided cryptographic signature or checksum before installation. - Install the verified artifact using the minimum required privileges. - Provide manual inspection instructions and fail closed if verification fails. - Avoid recommending root execution when user-level installation is sufficient. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:7
Finding
Mutable Personal Git Repository Is Cloned and Later Executed Without Integrity Verification<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:7-18` **Vulnerability Type**: Unpinned remote code retrieval and execution **Risk Level**: High ### Complete Code Snippet ```bash ## 仓库源 https://github.com/Yuandiaodiaodiao/opinion-skill 如果本地没有 scripts 目录,先克隆仓库: ```bash git clone https://github.com/Yuandiaodiaodiao/opinion-skill.git /root/opinionskills ``` ## 环境检查 ```bash ls /root/opinionskills/scripts/config.ts 2>/dev/null && echo "scripts ready" || { echo "scripts missing, cloning..."; git clone https://github.com/Yuandiaodiaodiao/opinion-skill.git /root/opinionskills; } ``` ``` The cloned scripts are subsequently executed through documented commands such as: ```bash bun run scripts/enable-trading.ts bun run scripts/buy.ts --market <ID> --token <tokenId> --price 0.45 --amount 10 ``` ### Technical Analysis The fallback instructions clone the mutable default branch of a personal GitHub repository. No commit hash, signed tag, archive checksum, or other integrity control binds the downloaded repository to the version that was audited. The existence check verifies only that `scripts/config.ts` is present. It does not verify the origin or integrity of any script. A repository takeover, account compromise, force-push, or malicious future commit could therefore replace the reviewed code with arbitrary TypeScript. The documented workflow later places wallet credentials in `/root/opinionskills/.env` and executes the cloned scripts with Bun. This gives changed repository code direct access to those credentials and the host user's permissions. ### Attack Path 1. The expected local `scripts` directory or `config.ts` file is absent. 2. The fallback command clones the current default branch from the remote repository. 3. The user creates `.env` containing a wallet private key and API credentials. 4. The user runs one of the cloned TypeScript scripts with Bun. 5. Malicious code introduced through repository compromise executes locally. 6. It can r ...[truncated 525 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Package the audited scripts directly with the Skill and remove automatic cloning. - If remote retrieval is unavoidable, pin a specific reviewed commit hash. - Download a fixed archive and verify a published cryptographic checksum or signature before use. - Reject unexpected repository state, unsigned updates, and branch movement. - Do not store wallet credentials in a directory containing mutable, remotely sourced code. - Require an explicit review and update process before adopting new repository revisions. - Run trading scripts under a dedicated, non-root account with narrowly scoped filesystem access. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/config.ts:8
Finding
Market and Wallet Data Are Transmitted over Unencrypted HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/config.ts:8-20` **Vulnerability Type**: Cleartext network communication and unauthenticated market data **Risk Level**: High ### Complete Code Snippet ```ts const OPINION_API_HOST = "http://newopinion.predictscanapi.xyz:10001"; // 轻量 fetch wrapper, 不依赖 axios async function apiFetch<T = any>(path: string, params?: Record<string, any>): Promise<T> { const url = new URL(path, OPINION_API_HOST); if (params) { for (const [k, v] of Object.entries(params)) { if (v !== undefined && v !== null) url.searchParams.set(k, String(v)); } } const resp = await fetch(url.toString(), { signal: AbortSignal.timeout(30000) }); if (!resp.ok) throw new Error(`API ${resp.status}: ${resp.statusText}`); return resp.json() as Promise<T>; } ``` This shared wrapper is used by market, price, order-book, trade, and position-query scripts. For example, `scripts/positions.ts:6-7` sends a wallet address in the URL: ```ts async function getPositions(address: string, limit: number, json: boolean): Promise<void> { const resp = await apiFetch<any>(`/api/user/positions/${address}`, { limit, includeConditionId: "true" }); ``` ### Technical Analysis The API host uses plain HTTP rather than HTTPS. Requests and responses therefore lack transport confidentiality and authenticated integrity. Network observers can inspect wallet addresses, search terms, market identifiers, and asset identifiers. An active network attacker can also modify returned market details, positions, prices, or order-book data. These outbound requests are necessary for the Skill's declared query functionality, and the audited first-party code does not attach the wallet private key to this endpoint. However, unencrypted transport is not necessary and does not satisfy least-privilege handling of wallet-related information. The integrity risk is financially significant because `buy.ts` and `sell.ts` retrieve and display prices through thi ...[truncated 1002 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace the HTTP endpoint with an authenticated HTTPS endpoint. - Validate certificates using the runtime's standard trusted certificate store. - Reject redirects that downgrade HTTPS to HTTP. - Fail closed if secure transport is unavailable. - Consider separating public market-data requests from wallet-related portfolio queries. - Do not use unauthenticated market data as the sole reference for a financial operation. - Where supported, validate critical market identifiers and price information against the official SDK or an independent trusted source before placing an order. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/market-cache.ts:42
Finding
Unauthenticated Search Path Implicitly Reads and Transmits an Ambient API Key<![CDATA[ ## Vulnerability Details **File Location**: `scripts/market-cache.ts:42-57` **Vulnerability Type**: Excessive ambient credential use **Risk Level**: Medium ### Complete Code Snippet ```ts async function openapiFetch(path: string, params?: Record<string, any>): Promise<any> { // path 是相对路径如 "/market", 拼接到 OPENAPI_BASE 末尾 const base = OPENAPI_BASE.endsWith("/") ? OPENAPI_BASE : OPENAPI_BASE + "/"; const url = new URL(path.replace(/^\//, ""), base); if (params) { for (const [k, v] of Object.entries(params)) { if (v !== undefined && v !== null) url.searchParams.set(k, String(v)); } } const headers: Record<string, string> = {}; const apiKey = process.env.API_KEY; if (apiKey) headers["apikey"] = apiKey; const resp = await fetch(url.toString(), { headers, signal: AbortSignal.timeout(30000) }); if (!resp.ok) throw new Error(`OpenAPI ${resp.status}: ${resp.statusText}`); return resp.json(); } ``` The cache function is automatically reached by the search workflow in `scripts/search.ts:42-50`: ```ts const [apiPromise, cachePromise] = [ apiFetch<any>("/api/markets/search", { q: keyword, limit }).catch(() => null), getMarkets(refresh).then(m => fuzzySearch(m, keyword, limit)).catch(() => [] as SearchResult[]), ]; const [apiResp, cacheResults] = await Promise.all([apiPromise, cachePromise]); ``` ### Technical Analysis The documentation describes search and market-data scripts as requiring no environment variables. Nevertheless, the market-cache implementation automatically reads the generic ambient variable `API_KEY` and sends it to `https://openapi.opinion.trade` whenever that variable exists. The destination is consistent with the declared Opinion market functionality, and there is no evidence that the code sends the private key. However, implicit use of a generic environment variable exceeds the minimum privilege needed for the advertised unauthenticated search path. A key intended for another service or a differ ...[truncated 1081 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not attach credentials to endpoints that support unauthenticated access. - Replace the generic `API_KEY` variable with an explicitly scoped name such as `OPINION_OPENAPI_KEY`. - Require explicit configuration before enabling authenticated OpenAPI requests. - Keep public market search and authenticated trading configuration separate. - Document the exact destination, header, and purpose of every transmitted credential. - Validate that the configured key belongs to the expected service before use. - Prefer a minimal child-process environment rather than inheriting all shell variables. ]]>

T08 · Insecure Dependencies

Warning
Location
package.json:21
Finding
Trading Dependencies Are Mutable and Lack a Lockfile<![CDATA[ ## Vulnerability Details **File Location**: `package.json:21-24` **Vulnerability Type**: Non-reproducible third-party dependency resolution **Risk Level**: Medium ### Complete Code Snippet ```json "dependencies": { "@opinion-labs/opinion-clob-sdk": "^0.5.3", "axios": "^1.7.0" } ``` No dependency lockfile is present in the supplied project structure. The SDK receives sensitive trading credentials in `scripts/sdk-config.ts:34-42`: ```ts return new Client({ host: SDK_API_HOST, apiKey: API_KEY, chainId: CHAIN_ID_BNB_MAINNET, rpcUrl: BSC_RPC, privateKey: PRIVATE_KEY as `0x${string}`, multiSigAddress: MULTI_SIG_ADDRESS as `0x${string}`, }); ``` ### Technical Analysis Caret version ranges allow future semver-compatible package versions to be selected during installation. Without a lockfile, transitive dependency versions are also resolved at installation time rather than being bound to the versions reviewed during the audit. This is especially sensitive because the Opinion SDK receives the wallet private key, API key, RPC URL, and multisig address. A compromised future SDK release or transitive dependency could access these values at runtime. Dependency lifecycle scripts could also execute during installation with the user's filesystem and environment privileges. The audit did not establish that the named packages are currently malicious. The vulnerability is the absence of reproducible and integrity-bound dependency resolution. ### Attack Path 1. A user follows the instructions and runs `bun install`. 2. The package resolver selects versions allowed by the caret ranges at that time. 3. A compromised future release or transitive package is downloaded. 4. Malicious lifecycle or runtime code executes with the user's privileges. 5. When a trading script constructs the SDK client, the dependency can access the wallet private key and API key. 6. The dependency can exfiltrate credentials, alter signed orders, or misuse the wallet. ### ...[truncated 370 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin dependencies to exact reviewed versions rather than caret ranges. - Generate and commit a Bun-compatible lockfile. - Require frozen-lockfile installation in documentation and automation. - Verify package provenance and integrity metadata before installation. - Review direct and transitive dependency updates before changing the lockfile. - Disable dependency lifecycle scripts where they are not required. - Remove `axios` if it is unused, reducing the dependency attack surface. - Run dependency installation and trading scripts as a dedicated non-root user. - Consider isolating private-key signing from the broader SDK process through a narrowly scoped signer or hardware wallet. ]]>
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 Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (27)

External Script Fetching

High
Category
Supply Chain
Content
1. 安装 bun:
   ```bash
   command -v bun >/dev/null 2>&1 && echo "bun $(bun --version)" || { curl -fsSL https://bun.sh/install | bash && source ~/.bashrc; }
   ```
2. 创建 `.env` 文件:
   ```
Confidence
97% confidence
Finding
The skill instructs users to execute a remote installation script via 'curl ... | bash', which grants arbitrary code from an external server immediate shell execution on the host. Because this skill also operates in a sensitive context involving trading credentials and private keys, compromise of the runtime environment could lead to theft of wallet secrets, tampering with trades, or full host compromise.

Credential Access

High
Category
Privilege Escalation
Content
执行交易操作前,先确认 `.env` 是否已配置:
```bash
test -f /root/opinionskills/.env && grep -q "PRIVATE_KEY=0x" /root/opinionskills/.env && echo "Trading credentials configured" || echo "WARNING: .env not configured — only market data queries are available. To trade, create /root/opinionskills/.env with PRIVATE_KEY, MULTI_SIG_ADDRESS, and API_KEY."
```

如果用户要求下单但 `.env` 未配置,不要执行交易脚本,而是提示用户先配置环境变量。
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Ae1

High
Category
analysis-evasion
Content
bun run scripts/price.ts <assetId> [<assetId2> ...] [--json] # 查询价格
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
bun run scripts/orderbook.ts <assetId> [--json] # 查看订单簿
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
bun run scripts/orderbook.ts <assetId> [--json] # 查看订单簿
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
bun run scripts/trades.ts <assetId> [--limit <n>] [--filter all|taker|maker] [--json] # 成交记录
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
bun run scripts/top-markets.ts [--tag volume|txn] [--window 1h|4h|24h] [--json] # 热门市场
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Credential Access

High
Category
Privilege Escalation
Content
function getClient(): Client {
  if (!PRIVATE_KEY) {
    console.error("Error: set PRIVATE_KEY in .env");
    process.exit(1);
  }
  if (!MULTI_SIG_ADDRESS) {
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
function getClient(): Client {
  if (!PRIVATE_KEY) {
    console.error("Error: set PRIVATE_KEY in .env");
    process.exit(1);
  }
  if (!MULTI_SIG_ADDRESS) {
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
function getClient(): Client {
  if (!PRIVATE_KEY) {
    console.error("Error: set PRIVATE_KEY in .env");
    process.exit(1);
  }
  if (!MULTI_SIG_ADDRESS) {
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The natural-language instructions throughout the skill file are presented exclusively in Chinese, which effectively forces a specific language for users. The policy allows locale constraints only when users are given a choice or when the constraint is clearly documented and justified, neither of which appears here.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The file's natural-language interface is presented in Chinese only, including the purpose and usage guidance. This imposes a specific language on users without any opt-in, alternative locale, or documented region-specific justification, which matches the language/locale policy violation category.

Natural-Language Policy Violations

Medium
Confidence
86% confidence
Finding
The comments are written entirely in Chinese and indicate intended usage only in that language context, with no indication that users may choose another language or locale. Per the policy, forcing a specific language without opt-in can be a natural-language policy violation unless clearly justified.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
This code file contains natural-language instructions in comments that force a specific language context for readers. The policy calls for flagging language or locale constraints when the skill does not offer user opt-in or justify the restriction.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
This TypeScript file contains natural-language comments and user-facing output in Chinese, such as the top-level file description and cache-status messaging. Because the skill does not offer a language option or justify that it is intentionally region-specific, it violates the language/locale policy for natural-language content.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
With no manifest available, the skill's intended scope is unknown, so accessing process environment for credentials is an extra capability that is not justified by any declared purpose. The rest of the file is primarily market-data caching and fuzzy search logic, making secret retrieval a distinct capability requiring explicit intent declaration.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The file loads highly sensitive values from environment variables and then exports them module-wide, including the private key and API key. Exporting raw credentials increases the chance that other parts of the codebase accidentally log, leak, or misuse them, especially in a trading script context where the private key directly authorizes on-chain actions.

Natural-Language Policy Violations

Medium
Confidence
85% confidence
Finding
This TypeScript file contains natural-language comments and usage guidance in Chinese only, such as the file description and usage instructions. Under the policy, forcing a specific language without user opt-in or documented justification is a locale/language policy violation.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"enable-trading": "bun run scripts/enable-trading.ts"
  },
  "dependencies": {
    "@opinion-labs/opinion-clob-sdk": "^0.5.3",
    "axios": "^1.7.0"
  }
}
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "dependencies": {
    "@opinion-labs/opinion-clob-sdk": "^0.5.3",
    "axios": "^1.7.0"
  }
}
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Unverifiable Dependency: axios has 16 known advisory(ies) (CVE-2026-44494 (axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co); CVE-2026-44495 (axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut); CVE-2025-62718 (Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
79% confidence
Finding
The manifest references axios with a non-exact version and no visible lockfile context, while axios has multiple published advisories including SSRF- and proxy-related issues in some versions. In a trading skill that likely makes outbound API requests and may handle credentials or network configuration, an unresolved vulnerable axios version could expose requests, tokens, or routing controls if a susceptible release is installed.

Missing User Warnings

Low
Confidence
81% confidence
Finding
This TypeScript file performs an outbound HTTP request via fetch, which can transmit query parameters derived from caller-supplied data to an external host. There is no visible confirmation prompt, user-facing log, or explanatory comment warning that request parameters may be sent over the network.

Intent-Code Divergence

Low
Confidence
78% confidence
Finding
The interface comment documents marketType values as 0 and 1 only, yet the fetch call uses marketType: 2 with an inline comment claiming it means all types. This is an active documentation contradiction about the meaning of a key request parameter, which can mislead reviewers about what data is actually retrieved.

Missing User Warnings

Low
Confidence
83% confidence
Finding
This code sends the user-provided wallet address to `/api/user/positions/${address}` and then submits derived asset IDs to a batch markets endpoint. Although the script name suggests position lookup, there is no explicit disclosure in comments, help text, or runtime output that external API calls will transmit portfolio-related identifiers and data.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
The file’s user-facing natural language is exclusively Chinese in the header comments and usage description, with no indication of alternative language support or user choice. Under the stated policy, forcing a specific language without opt-in is a natural-language policy concern.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/market-cache.ts:52