Back to skill

Security audit

Agent Onchain Watch

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its on-chain monitoring purpose, but it can silently return fake blockchain results and mislabel chain data, so it should be reviewed before use.

Review before installing. Do not rely on this for real wallet, compliance, or incident monitoring until the mock fallback is removed or explicitly labeled, unsupported chains are rejected or correctly mapped, outbound LLM data sharing is documented, and dependencies are audited.

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

T09 · Insecure Skill Coding Practices

Error
Location
src/fetcher.ts:23
Finding

Fabricated On-Chain Data Returned as Genuine Results When the Etherscan Key Is Missing

Content
View full analysis

Vulnerability Details

File Location: src/fetcher.ts:23-25, 62, 78-103, 126-139
Vulnerability Type: Silent production fallback to fabricated financial data
Risk Level: High

Complete Code Snippet:

ts
async function callEtherscan(params: Record<string, string>): Promise<unknown> {
  // API 키 없을 경우 Mock 반환 (테스트용)
  if (!process.env.ETHERSCAN_API_KEY) {
    console.warn('[Etherscan] API 키 없음. Mock 데이터 반환.');
    return null; // Mock 데이터는 개별 함수에서 처리하거나 여기서 분기 가능
  }
ts
export async function fetchBalance(address: string): Promise<number | null> {
  console.log(`[Fetcher] 잔액 조회: ${address}`);

  if (!process.env.ETHERSCAN_API_KEY) return 1.2345; // Mock Balance
}
ts
export async function fetchTransactions(address: string): Promise<TxRecord[]> {
  console.log(`[Fetcher] 트랜잭션 조회: ${address}`);

  if (!process.env.ETHERSCAN_API_KEY) {
    // Mock Transactions
    return [
      {
        hash: '0xmockhash1',
        from: '0xSender',
        to: address,
        value_eth: 5.0,
        timestamp: new Date().toISOString(),
        type: 'in'
      },
      {
        hash: '0xmockhash2',
        from: address,
        to: '0xReceiver',
        value_eth: 12.5,
        timestamp: new Date(Date.now() - 60000).toISOString(),
        type: 'out'
      }
    ];
  }
ts
export async function fetchTokenTransfers(address: string): Promise<TokenTransferRecord[]> {
  console.log(`[Fetcher] 토큰 전송 조회: ${address}`);

  if (!process.env.ETHERSCAN_API_KEY) {
    // Mock Token Transfers
    return [
      {
        token_name: 'USDC',
        token_symbol: 'USDC',
        from: '0xSender',
        to: address,
        value: '1000000000',
        timestamp: new Date().toISOString()
      }
    ];
  }
}

Technical Analysis

The production data-access functions silently return fixed ...[truncated 1941 chars]

Remediation
View remediation

Remediation Suggestions

  • Fail closed when ETHERSCAN_API_KEY is unavailable and return an explicit configuration error.
  • Remove mock responses from production data-access functions.
  • Place mock implementations in a separate test adapter that can only be selected through an explicit test configuration such as NODE_ENV === "test".
  • Add a startup configuration check so the process cannot advertise readiness without required credentials.
  • If demonstration mode is required, require an explicit opt-in flag and include an unambiguous data_source: "mock" marker in every response.
  • Add automated tests verifying that missing production credentials result in an error rather than a successful report.

T09 · Insecure Skill Coding Practices

Warning
Location
src/handler.ts:25
Finding

Caller-Supplied Chain Is Echoed While All Queries Are Hard-Coded to Ethereum Mainnet

Content
View full analysis

Vulnerability Details

File Location: src/handler.ts:25-28; src/fetcher.ts:28-30
Vulnerability Type: Insufficient input validation and cross-chain result mislabeling
Risk Level: Medium

Complete Code Snippet:

ts
const chain = input.chain ?? 'ethereum';
const eventTypes = input.event_types ?? ['tx', 'token_transfer'];

console.log(`[Handler] 시작 | address: ${address} | chain: ${chain}`);
ts
const url = new URL('https://api.etherscan.io/v2/api');
url.searchParams.set('chainid', '1'); // Ethereum Mainnet
url.searchParams.set('apikey', process.env.ETHERSCAN_API_KEY!);

The supplied value is subsequently returned unchanged:

ts
const output: OnchainWatchOutput = {
  address,
  chain,
  balance_eth: balance,
  transactions: txList,
  token_transfers: tokenList,
  risk_flags: riskFlags,
  summary,
};

Technical Analysis

The handler accepts an arbitrary chain value and preserves it in the output, but the Etherscan client always uses chainid=1, corresponding to Ethereum mainnet. No allowlist, normalization, or consistency check links the requested chain to the chain that is actually queried.

Ethereum-compatible networks share the same address format, so the address validator does not prevent this mismatch. Consequently, valid Ethereum-mainnet data can be labeled as belonging to another requested network.

This is an output-integrity and validation flaw rather than a privilege-escalation issue. It is exploitable through the normal job payload without authentication bypass or control over the Etherscan endpoint.

Attack Path

  1. A caller submits a valid 42-character hexadecimal address and a non-Ethereum chain name.
  2. The handler accepts and records the supplied chain because no supported-chain validation is performed.
  3. The fetcher sends all balance and transaction requests with chainid=1.
  4. Ethereum-mainnet records are returned and analyzed ...[truncated 593 chars]
Remediation
View remediation

Remediation Suggestions

  • If only Ethereum is supported, reject any normalized chain value other than ethereum.
  • If multiple networks are intended, maintain an explicit allowlist mapping each supported chain name to its authoritative chain ID and endpoint.
  • Pass the validated chain ID into every fetch operation instead of hard-coding 1.
  • Return the normalized chain that was actually queried, not the unvalidated caller-supplied value.
  • Add tests for unsupported chains, aliases, casing, and consistency between requested chain, queried chain ID, and response metadata.
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
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (29)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Providing only a generic LLM-call interface while advertising specialized on-chain monitoring is a deceptive capability mismatch. This is especially risky in a security-analysis context because users may act on unsupported summaries or alerts, and may disclose addresses, incidents, or investigative notes to external services unintentionally.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

Providing only a generic LLM-call interface while advertising specialized on-chain monitoring is a deceptive capability mismatch. This is especially risky in a security-analysis context because users may act on unsupported summaries or alerts, and may disclose addresses, incidents, or investigative notes to external services unintentionally.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Providing only a generic LLM-call interface while advertising specialized on-chain monitoring is a deceptive capability mismatch. This is especially risky in a security-analysis context because users may act on unsupported summaries or alerts, and may disclose addresses, incidents, or investigative notes to external services unintentionally.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Providing only a generic LLM-call interface while advertising specialized on-chain monitoring is a deceptive capability mismatch. This is especially risky in a security-analysis context because users may act on unsupported summaries or alerts, and may disclose addresses, incidents, or investigative notes to external services unintentionally.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Providing only a generic LLM-call interface while advertising specialized on-chain monitoring is a deceptive capability mismatch. This is especially risky in a security-analysis context because users may act on unsupported summaries or alerts, and may disclose addresses, incidents, or investigative notes to external services unintentionally.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: form-data==4.0.5 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
93% confidence
Finding

The lockfile includes form-data 4.0.5, which is flagged with a high-severity advisory for CRLF injection via unescaped multipart field names. Because this package is pulled in transitively through @types/node-fetch, the issue is present in the dependency graph even though this file alone does not prove active exploitation; if any runtime code constructs multipart requests with attacker-controlled field names, it could enable request smuggling or header/body manipulation against downstream services.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · src/analyzer.ts (reported line 7)May include surrounding context.

ts
import * as path from 'path';
import { TxRecord, TokenTransferRecord } from './types';

// .env 직접 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Fetcher] API Key Check:', process.env.ETHERSCAN_API_KEY ? 'FOUND' : 'MISSING');

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · src/fetcher.ts (reported line 6)May include surrounding context.

ts
import * as path from 'path';
import { TxRecord, TokenTransferRecord } from './types';

// .env 직접 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Fetcher] API Key Check:', process.env.ETHERSCAN_API_KEY ? 'FOUND' : 'MISSING');

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · src/analyzer.ts (reported line 8)May include surrounding context.

ts
import { TxRecord, TokenTransferRecord } from './types';

// .env 직접 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Fetcher] API Key Check:', process.env.ETHERSCAN_API_KEY ? 'FOUND' : 'MISSING');

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · src/fetcher.ts (reported line 7)May include surrounding context.

ts
import { TxRecord, TokenTransferRecord } from './types';

// .env 직접 로드
dotenv.config({ path: path.resolve(__dirname, '../.env') });

console.log('[Fetcher] API Key Check:', process.env.ETHERSCAN_API_KEY ? 'FOUND' : 'MISSING');

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The primary skill description is written only in Korean, which imposes a specific language on users without any opt-in or alternative language option. This matches the policy category for language or locale constraints that are not documented as optional or justified.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
73% confidence
Finding

The skill declares network and environment-backed capabilities implicitly but does not scope or disclose them via explicit permissions or allowed-tools metadata. This weakens reviewability and policy enforcement, making it easier for a skill to access secrets or make outbound requests beyond what users expect.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The system prompt explicitly instructs the model to produce the summary in Korean. Under the policy rule, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is clearly justified, which is not indicated here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This TypeScript file contains natural-language comments and user-visible console messages entirely in Korean, including operational status and error output. Under the policy, forcing a specific language without user opt-in is a locale/language policy violation unless the constraint is clearly justified, which it is not here.

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 · src/fetcher.ts (reported line 28)May include surrounding context.

ts
return null; // Mock 데이터는 개별 함수에서 처리하거나 여기서 분기 가능
  }

  const url = new URL('https://api.etherscan.io/v2/api');
  url.searchParams.set('chainid', '1'); // Ethereum Mainnet
  url.searchParams.set('apikey', process.env.ETHERSCAN_API_KEY!);
  for (const [k, v] of Object.entries(params)) {

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This TypeScript file contains natural-language comments and error messages exclusively in Korean, including the returned user-facing validation errors. The policy for this category flags language or locale constraints when a skill forces a specific language without user opt-in, and this file provides no indication of a language choice or region-specific justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This file contains natural-language comments and console messages exclusively in Korean, including operational status outputs shown to users or operators. The provided policy requires flagging language or locale constraints when the skill forces a specific language without opt-in, and no alternative language choice or justification is present here.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The adapter sends the full combined system prompt and user message to Google's external Gemini API, which can expose sensitive wallet, contract, or user-provided monitoring data to a third party without any visible user consent or disclosure in this code path. In an on-chain monitoring skill, prompts may contain addresses, internal heuristics, or operational context, so silent transmission increases privacy, compliance, and data-handling risk.

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 · src/llm/groq.ts (reported line 15)May include surrounding context.

ts
}
    this.client = new OpenAI({
      apiKey: config.apiKey,
      baseURL: 'https://api.groq.com/openai/v1',
    });
    this.model = config.model || 'llama-3.3-70b-versatile';
  }

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest description and usage text are presented in Korean only, which imposes a specific language on users without indicating any opt-in or alternative locale support. The policy explicitly calls for flagging language or locale constraints when they are forced without user choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The manifest description is written only in Korean ("지갑 및 컨트랙트 온체인 활동 모니터링 및 요약 에이전트"), which signals a fixed language choice in the skill metadata. Under the policy for natural-language violations, a language constraint should either offer user opt-in/choice or be clearly documented as region-justified.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
81% confidence
Finding

Using a caret range for @anthropic-ai/sdk allows automatic adoption of future minor/patch releases, which can introduce supply-chain risk if an upstream release is compromised or contains a breaking security regression. In an agent that processes on-chain monitoring data and likely handles API credentials, unexpected dependency changes can affect runtime behavior and trust boundaries.

Content

Scanner excerpt · package.json (reported line 15)May include surrounding context.

json
"author": "KimCode",
  "license": "ISC",
  "dependencies": {
    "@anthropic-ai/sdk": "^0.33.1",
    "dotenv": "^16.4.7",
    "openai": "^6.27.0"
  },

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
80% confidence
Finding

Using a caret range for dotenv permits unreviewed upstream updates during install, which is a classic software supply-chain exposure. While the direct risk is low, this package influences environment variable handling, so a compromised release could affect secret loading or application startup behavior.

Content

Scanner excerpt · package.json (reported line 16)May include surrounding context.

json
"license": "ISC",
  "dependencies": {
    "@anthropic-ai/sdk": "^0.33.1",
    "dotenv": "^16.4.7",
    "openai": "^6.27.0"
  },
  "devDependencies": {

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
82% confidence
Finding

Using a caret range for openai means future minor/patch versions may be pulled in without review, creating avoidable supply-chain risk. Because this skill likely interacts with external AI APIs and may handle prompts, outputs, and credentials, an unvetted SDK update could alter request handling or introduce insecure behavior.

Content

Scanner excerpt · package.json (reported line 17)May include surrounding context.

json
"dependencies": {
    "@anthropic-ai/sdk": "^0.33.1",
    "dotenv": "^16.4.7",
    "openai": "^6.27.0"
  },
  "devDependencies": {
    "@types/node": "^22.10.2",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 20)May include surrounding context.

json
"openai": "^6.27.0"
  },
  "devDependencies": {
    "@types/node": "^22.10.2",
    "ts-node": "^10.9.2",
    "typescript": "^5.7.2"
  }