Back to skill

Security audit

UPBIT market data get skill

Security checks for vulnerabilities and agentic risk

Overview

This market-data skill mostly does what it says, but it unnecessarily asks users to configure financial exchange API secrets and includes dormant authentication code for public-only commands.

Review before installing. Use this only with blank Upbit API key fields unless you have audited and need private API support, and do not place trading or withdrawal-capable exchange keys in the documented JSON config. Prefer a version with the unused auth code removed and dependencies pinned with a committed lockfile.

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

Warning
Location
src/upbit/auth.js:11
Finding

Unnecessary Plaintext Exchange Credential Handling

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:34-46, src/config.js:9-25, src/upbit/auth.js:11-31
Vulnerability Type: Unnecessary plaintext secret storage and access
Risk Level: Medium

The documentation encourages users to place Upbit access and secret keys in a plaintext JSON configuration file:

json
{
  "upbit": {
    "baseUrl": "https://api.upbit.com",
    "accessKey": "",
    "secretKey": ""
  },
  "watchlist": ["KRW-BTC", "KRW-ETH", "KRW-SOL"]
}

The configuration loader reads the complete file without enforcing restrictive permissions or separating secrets from non-sensitive settings:

js
function loadConfig() {
  if (cachedConfig) return cachedConfig;

  const configPath = process.env.UPBIT_SKILL_CONFIG
    ? path.resolve(process.env.UPBIT_SKILL_CONFIG)
    : DEFAULT_PATH;

  if (!fs.existsSync(configPath)) {
    throw new UpbitError(`Config file not found: ${configPath}`);
  }

  const raw = fs.readFileSync(configPath, "utf8");
  try {
    cachedConfig = JSON.parse(raw);
  } catch (err) {
    throw new UpbitError("Invalid JSON format in config file", { configPath });
  }

  return cachedConfig;
}

Authentication code then retrieves both credentials and can construct a bearer token containing the access key:

js
function createJwt({ queryString = "" } = {}) {
  const cfg = loadConfig();
  const accessKey = cfg?.upbit?.accessKey;
  const secretKey = cfg?.upbit?.secretKey;

  if (!accessKey || !secretKey) {
    throw new UpbitError("Missing upbit.accessKey / upbit.secretKey in config");
  }

  const payload = {
    access_key: accessKey,
    nonce: uuidv4()
  };

  if (queryString) {
    const queryHash = crypto.createHash("sha512").update(queryString, "utf8").digest("hex");
    payload.query_hash = queryHash;
    payload.query_hash_alg = "SHA512";
  }

  return jwt.sign(payload, secretKey, { algorithm: "HS512" });

...[truncated 2255 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove accessKey and secretKey from the documented configuration schema because public market-data endpoints do not require authentication.
  2. Remove src/upbit/auth.js and its authentication-only dependencies unless private API functionality is deliberately introduced.
  3. Keep watchlist configuration separate from any future secret-bearing configuration.
  4. If private API support is added later, obtain secrets from a dedicated secret manager or protected environment variables rather than ordinary JSON.
  5. Validate restrictive permissions on any unavoidable credential file and document that it must be excluded from source control and backups.
  6. Require least-privileged, read-only API keys wherever possible.
  7. Before enabling authenticated requests, restrict the destination to the exact expected HTTPS Upbit origin and prevent credentials from being sent to a configurable arbitrary host.

T08 · Insecure Dependencies

Note
Location
package.json:10
Finding

Non-Reproducible Installation of Authentication Dependencies

Content
View full analysis

Vulnerability Details

File Location: package.json:10-13, SKILL.md:24-28
Vulnerability Type: Unpinned dependency resolution without a committed lockfile
Risk Level: Low

The package declares mutable semantic-version ranges:

json
"dependencies": {
  "jsonwebtoken": "^9.0.2",
  "uuid": "^10.0.0"
}

Installation instructions direct users to resolve dependencies with a normal installation:

bash
npm install

No package lockfile was present in the audited project structure.

Technical Analysis

Caret version ranges permit later compatible releases to be selected during installation. Without a committed lockfile, the exact dependency graph installed in the future may differ from the versions that were available or reviewed during this audit.

This does not establish that either named package is currently malicious or vulnerable. The security concern is that installation is not reproducible and remains exposed to future upstream package compromise, dependency takeover, or unexpected transitive dependency changes.

Both dependencies support the dormant authentication path and are unnecessary for the currently exposed public market-data commands. Their presence therefore expands the supply-chain attack surface without supporting required functionality.

Attack Path

  1. A permitted future version of a direct or transitive dependency is compromised or otherwise contains malicious code.
  2. A user runs the documented npm install command after that version becomes available.
  3. npm resolves the mutable range to the affected release because no reviewed lockfile constrains the dependency graph.
  4. Malicious package code executes through an installation lifecycle script or when the Skill imports and invokes the dependency.
  5. The code receives the permissions of the installing user or the runtime Skill process.

This path is conditional on a future or upstream dependency compromise; no ...[truncated 490 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove jsonwebtoken and uuid while authentication remains unused.
  2. If these packages are required in the future, generate and commit a reviewed lockfile.
  3. Use npm ci in deployment and automation so installation follows the committed dependency graph.
  4. Review resolved direct and transitive versions and run dependency vulnerability checks regularly.
  5. Consider pinning exact direct dependency versions where operationally appropriate.
  6. Restrict or disable package lifecycle scripts in sensitive build environments when compatible with required dependencies.
  7. Reassess authentication dependencies before enabling any private Upbit API operations.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · src/upbit/client.js (reported line 17)May include surrounding context.

js
return items.join("&");
}

async function request({ method = "GET", path, query, authRequired = false }) {
  const cfg = loadConfig();
  const baseUrl = cfg?.upbit?.baseUrl || "https://api.upbit.com";

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency uses a caret range (^9.0.2), which permits installation of newer minor/patch releases rather than a single audited version. In a security-sensitive package, this weakens build reproducibility and can unintentionally introduce vulnerable or malicious upstream changes through the supply chain.

Content

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

json
"start": "node skill.js"
  },
  "dependencies": {
    "jsonwebtoken": "^9.0.2",
    "uuid": "^10.0.0"
  }
}

Unverifiable Dependency: jsonwebtoken has 4 known advisory(ies) (CVE-2022-23539 (jsonwebtoken unrestricted key type could lead to legacy keys usage ); CVE-2015-9235 (Verification Bypass in jsonwebtoken); CVE-2022-23541 (jsonwebtoken's insecure implementation of key retrieval function could lead to F) +1 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
82% confidence
Finding

The manifest references jsonwebtoken without an exact version, while the package has multiple historical advisories. Because the actual installed version cannot be determined from this file alone, there is a real risk that a vulnerable release could be resolved in some environments.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The uuid dependency is also specified with a caret range (^10.0.0), so installations may resolve to different releases over time. This creates supply-chain risk and makes it harder to verify that deployments consistently use a reviewed, non-vulnerable version.

Content

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

json
},
  "dependencies": {
    "jsonwebtoken": "^9.0.2",
    "uuid": "^10.0.0"
  }
}

Unverifiable Dependency: uuid has 1 known advisory(ies) (CVE-2026-41907 (uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
76% confidence
Finding

The uuid dependency is not pinned, and the package has at least one advisory noted by the scanner. Without an exact version or lockfile evidence, it is not possible to verify whether installations avoid the affected release, leaving a residual supply-chain exposure.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.