Back to skill

Security audit

Upbit Trading Skill

Security checks for vulnerabilities and agentic risk

Overview

The skill is not clearly malicious, but it asks for exchange credentials and runs an unreviewed external script through unsafe shell execution while overstating what the trading bot actually does.

Install only after reviewing and fixing the external GLM execution path and shell invocation. Use restricted Upbit API keys with no withdrawal permission, prefer a test or low-balance account, and do not rely on the advertised automated-trading or Telegram behavior unless the missing pieces are supplied and reviewed.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
realtime-bot.js:43
Finding

Shell Command Injection Through Position Market Data

Content
View full analysis
p.status === 'open'); for (const pos of openPositions) { const currentPrice = await getPrice(pos.market); const entryPrice = pos.entryPrice || pos.avgPrice; const pnlPercent = (currentPrice - entryPrice) / entryPrice; const prompt = `당신은 암호화폐 트레이딩 봇입니다. 포지션: ${pos.market} 진입가: ${entryPrice}원 현재가: ${currentPrice}원 손익: ${(pnlPercent * 100).toFixed(2)}% 목표: +5%, 손절: -5% 다음 중 하나만 답하세요: 1. HOLD - 유지 2. SELL_NOW - 즉시 매도 (목표/손절 전이라도) 3. ADJUST:새목표,새손절 - 목표/손절 조정 응답 형식: HOLD, SELL_NOW, 또는 ADJUST:5,-3`; const response = askGLM(prompt); ``` ### Technical Analysis `execSync()` receives a dynamically constructed command string and consequently invokes a shell. The code attempts to protect the prompt by escaping double quotes, but this does not make content safe inside a shell double-quoted argument. Shell constructs including command substitution remain active within double quotes. For example, `$(command)` and backtick substitutions can still be evaluated. Because `pos.market` is loaded from the locally writable `positions.json` file and interpolated into the prompt without strict validation, a malicious market value can introduce shell syntax. This is an injection flaw rather than merely malformed argument handling: attacker-controlled te ...[truncated 1597 chars]
Remediation
View remediation

T07 · Tool Hijacking and Spoofing

Error
Location
realtime-bot.js:43
Finding

Execution of an Unverified Script Outside the Audited Skill Directory

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
realtime-bot.js:55
Finding

Unbounded Repeated Event Generation Can Exhaust Local Resources

Content
View full analysis
= CONFIG.targetProfit) { addEvent({ type: 'TARGET_HIT', market: pos.market, entryPrice, currentPrice, pnlPercent, message: `🎯 ${pos.market} 목표 도달! +${(pnlPercent * 100).toFixed(2)}%` }); } else if (pnlPercent <= CONFIG.stopLoss) { addEvent({ type: 'STOPLOSS_HIT', market: pos.market, entryPrice, currentPrice, pnlPercent, message: `🚨 ${pos.market} 손절 도달! ${(pnlPercent * 100).toFixed(2)}%` }); } ``` The check runs continuously: ```js mainLoop(); setInterval(mainLoop, CONFIG.priceCheckInterval); ``` ### Technical Analysis When an open position remains at or beyond the configured profit or loss threshold, each ten-second polling cycle appends another event for the same condition. There is no state-transition check, deduplication key, cooldown, maximum event count, file-size limit, archival policy, or log rotation. In addition, `addEvent()` reads and parses the entire event file, appends one object, serializes the entire array, and rewrites the whole file. Processing cost therefore increases as the file grows. Repeated events can progressively consume disk space, memory, and CPU. `setInterval()` also does not wait for a previous asynchronous `mainLoop()` call to finish before scheduling another invocation. Slow network or AI operations can consequently produce overlapping iterations and further resourc ...[truncated 1384 chars]
Remediation
View remediation
setTimeout(resolve, delay)); } } ``` 9. Add monitoring and alerts for event-file size, write failures, iteration duration, and overlapping work. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (18)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Advertising automated trading and technical analysis while those functions are not implemented, combined with undeclared local reads/writes of trade-related JSON state, creates a transparency and trust problem. Users may believe the bot is executing vetted strategies when it is instead performing different behavior, including persistence of potentially sensitive trading data.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Advertising automated trading and technical analysis while those functions are not implemented, combined with undeclared local reads/writes of trade-related JSON state, creates a transparency and trust problem. Users may believe the bot is executing vetted strategies when it is instead performing different behavior, including persistence of potentially sensitive trading data.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Advertising automated trading and technical analysis while those functions are not implemented, combined with undeclared local reads/writes of trade-related JSON state, creates a transparency and trust problem. Users may believe the bot is executing vetted strategies when it is instead performing different behavior, including persistence of potentially sensitive trading data.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
85% confidence
Finding

The documentation explicitly instructs users to create a .env file containing exchange API access and secret keys. In a financial automation skill, requesting high-value credentials is inherently sensitive; if the skill is misleading or mishandles secrets, users could lose account confidentiality or authorize unwanted trading actions.

Content

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

  1. 환경변수 설정:
bash
cp .env.example .env
# UPBIT_ACCESS_KEY, UPBIT_SECRET_KEY 입력

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `realtime-bot.js` - 메인 봇

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 · balance.js (reported line 4)May include surrounding context.

js
#!/usr/bin/env node
// 업비트 잔고 조회

require('dotenv').config({ path: __dirname + '/.env' });
const jwt = require('jsonwebtoken');
const { v4: uuidv4 } = require('uuid');
const axios = require('axios');

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill advertises functionality that would require environment-variable access and network connectivity, but it does not explicitly declare tool scope or permissions. In an automation/trading context, this weakens transparency and reviewability, making it harder for users and platforms to understand what sensitive capabilities the skill expects to use.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill promotes automated real-time trading but omits warnings about financial loss, unintended orders, and account impact. In a live trading context, the absence of risk disclosure makes unsafe use more likely because users may treat the tool as low-risk automation rather than software that can directly affect assets.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The setup instructions tell users to place Upbit API credentials into a .env file without explaining secure handling, least-privilege API scopes, or the risk of granting trading authority. Because exchange API keys can expose balances and enable orders, weak credential guidance materially increases the chance of account compromise or misuse.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script accesses exchange API credentials via environment variables to authenticate against a live Upbit account. While this is part of the script's functionality, there is no doc comment, warning, or other user-facing disclosure that the skill consumes sensitive credentials.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · balance.js (reported line 21)May include surrounding context.

js
const token = jwt.sign(payload, SECRET_KEY);
  
  try {
    const response = await axios.get('https://api.upbit.com/v1/accounts', {
      headers: { Authorization: `Bearer ${token}` }
    });

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · realtime-bot.js (reported line 45)May include surrounding context.

js
const token = jwt.sign(payload, SECRET_KEY);
  
  try {
    const response = await axios.get('https://api.upbit.com/v1/accounts', {
      headers: { Authorization: `Bearer ${token}` }
    });

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code sends an authenticated request containing a bearer token derived from the user's API keys to api.upbit.com. Although balance retrieval is the apparent purpose, the file itself does not include any warning or disclosure that account data will be transmitted to an external service.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest description says '자동매매' (automated trading), implying the skill performs buy/sell actions. In this file, the code fetches prices, queries GLM, and appends signals like TARGET_HIT, GLM_SELL_SIGNAL, and GLM_ADJUST to events.json, but never calls any Upbit authenticated trading endpoint or otherwise executes an order.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The log function hard-codes the locale to 'ko-KR' and timezone to 'Asia/Seoul'. This is a natural-language/locale policy issue because the skill enforces a specific locale presentation without offering user opt-in or documenting that the tool is intentionally region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

Natural-language content in the manifest and README is presented exclusively in Korean, including the description, features, and setup steps. This can violate language/locale policy expectations when no user opt-in or explicit region-specific justification is provided.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This JavaScript file contains user-facing and instructional natural language exclusively in Korean, including comments and CLI test output. Under the language/locale policy rule, forcing a specific language without user opt-in or justification can be a policy violation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The file header states 'Upbit 실시간 모니터링 봇' and documents price checks, GLM analysis, and event logging only. That documentation conflicts with the broader skill-level claim of '자동매매', creating an intent/code documentation divergence about whether the bot merely monitors or actually trades.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.env_credential_access

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
realtime-bot.js:53

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
balance.js:9