Back to skill

Security audit

Crypto Portfolio Tracker API

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a normal crypto price tracker, but it has under-disclosed credential and supply-chain risks users should review before installing.

Review the package identity before installing, prefer a pinned version or lockfile-managed install, and avoid running unpinned npx commands. Do not set PRISM_API_KEY in an environment where untrusted code can pass a custom baseUrl to PortfolioTracker, because that key may be sent to the configured endpoint.

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/index.js:9
Finding
Environment API Key Can Be Exfiltrated Through a Caller-Controlled Base URL<![CDATA[ ## Vulnerability Details **File Location**: `src/index.js:9-11` and `src/index.js:55-62` **Vulnerability Type**: Credential disclosure through an untrusted network destination **Risk Level**: Medium ### Vulnerable Code ```javascript class PortfolioTracker { constructor(options = {}) { this.apiKey = options.apiKey || process.env.PRISM_API_KEY || null; this.baseUrl = options.baseUrl || PRISM_BASE; this.holdings = new Map(); } ``` ```javascript async fetchPrices() { const symbols = Array.from(this.holdings.keys()); if (symbols.length === 0) return { prices: [] }; const url = `${this.baseUrl}/crypto/prices/batch?symbols=${symbols.join(',')}`; const headers = this.apiKey ? { 'X-API-Key': this.apiKey } : {}; const response = await fetch(url, { headers }); ``` ### Technical Analysis The constructor independently accepts a caller-controlled `baseUrl` while automatically reading `PRISM_API_KEY` from the process environment. `fetchPrices()` then sends that credential in the `X-API-Key` header to the configured URL without validating its protocol, hostname, port, or origin. A caller that can influence the constructor options does not need to know or explicitly provide the API key. Supplying only a malicious `baseUrl` is sufficient to cause the Skill to retrieve the credential from the environment and disclose it to the selected endpoint. The custom endpoint behavior is not documented as part of the declared portfolio-tracking functionality. Sending the key to arbitrary origins therefore exceeds the minimum network privilege required to retrieve prices from the documented Prism API. The request also discloses the symbols held in the portfolio through the `symbols` query parameter. Portfolio amounts and cost bases are not included in the network request. ### Attack Path 1. A legitimate application runs with `PRISM_API_KEY` in its environment. 2. An attacker influences configuration or code that constructs `PortfolioTracker`. ...[truncated 1390 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Send the Prism credential only when the destination origin exactly matches the trusted Prism API origin: ```javascript const PRISM_ORIGIN = new URL(PRISM_BASE).origin; const target = new URL('/crypto/prices/batch', this.baseUrl); if (target.origin === PRISM_ORIGIN && this.apiKey) { headers['X-API-Key'] = this.apiKey; } ``` 2. Remove configurable `baseUrl` support if it is not required by the public functionality. 3. If custom endpoints are required, do not implicitly reuse `PRISM_API_KEY`. Require callers to provide an explicit credential associated with that endpoint. 4. Restrict accepted URLs to HTTPS and reject URLs containing embedded credentials, unexpected ports, or malformed hostnames. 5. Where server-side request forgery is relevant, resolve and reject loopback, private, link-local, multicast, and cloud metadata destinations. Revalidate redirects or disable them. 6. Document that token symbols are sent to the selected pricing provider. 7. Add tests verifying that: - `PRISM_API_KEY` is sent to `https://api.prismapi.ai` only. - Custom origins never receive the environment credential. - HTTP and restricted network destinations are rejected. - Redirects cannot transfer credentials to another origin. ]]>

T08 · Insecure Dependencies

Note
Location
skill.json:7
Finding
Conflicting Package and Repository Identities Create Supply-Chain Confusion<![CDATA[ ## Vulnerability Details **File Location**: `skill.json:7-8`, with conflicting declarations in `package.json:2,33-35`, `README.md:15-17`, and `SKILL.md:12-14` **Vulnerability Type**: Package and repository identity confusion **Risk Level**: Low ### Vulnerable Metadata `skill.json` declares a scoped package and one repository: ```json { "name": "strykr-portfolio-tracker", "version": "1.0.0", "description": "Track crypto portfolio value, P&L, and allocation using Strykr Prism API. Supports BTC, ETH, SOL and 10,000+ tokens.", "author": "Strykr", "tags": ["crypto", "portfolio", "trading", "prices", "prism", "strykr"], "npm": "@strykr/portfolio-tracker", "repository": "https://github.com/Strykr-Ai/portfolio-tracker" } ``` `package.json` declares a different, unscoped package and repository: ```json { "name": "crypto-portfolio-tracker-api", "version": "1.0.0", "description": "Real-time cryptocurrency portfolio tracker API - Track Bitcoin, Ethereum, Solana holdings, P&L, allocation across 10,000+ tokens. REST API for trading bots, dashboards, and DeFi apps.", "main": "src/index.js", "bin": { "crypto-portfolio": "./cli.js" }, "repository": { "type": "git", "url": "https://github.com/Strykr-Prism/crypto-portfolio-tracker-api.git" } } ``` The installation documentation identifies the unscoped package: ```bash npm install crypto-portfolio-tracker-api ``` ### Technical Analysis Different metadata sources identify the audited Skill as different npm packages and GitHub repositories: - npm package in `skill.json`: `@strykr/portfolio-tracker` - npm package in `package.json` and documentation: `crypto-portfolio-tracker-api` - repository in `skill.json`: `Strykr-Ai/portfolio-tracker` - repository in `package.json`: `Strykr-Prism/crypto-portfolio-tracker-api` Installers, users, and automated security systems may rely on different metadata files. As a result, they can resolve or review an artifact other than the one i ...[truncated 1687 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Select one canonical npm package name and use it consistently in: - `package.json` - `skill.json` - `README.md` - `SKILL.md` - examples and source-code comments 2. Select one canonical repository URL and use it in all metadata files. 3. Prefer a verified organization-scoped npm package to reduce name-squatting risk. 4. Confirm ownership of every referenced package and repository before publishing the Skill. 5. Pin reviewed versions and integrity hashes in installer metadata where supported. 6. Add an automated release check that fails when package names, repository URLs, or installation instructions disagree. 7. Publish provenance or signed release attestations that bind the npm artifact to the canonical source repository and commit. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • 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 (6)

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The README instructs users to run the package via `npx crypto-portfolio-tracker-api` without pinning a specific version. Because `npx` fetches and executes the latest published package by default, a malicious update, account compromise, or dependency hijack could cause arbitrary code execution on the user's machine when they follow the documentation.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
This command example also uses unpinned `npx`, which executes whatever version is current in the registry at runtime. If the package or one of its publish paths is compromised, users invoking the documented command may unknowingly run attacker-controlled code.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The `track portfolio.json` example is another instance of direct execution of an unpinned package from the registry. In the context of a crypto portfolio tool, users may be particularly attractive targets, and arbitrary code execution could expose wallet-related files, API keys, or other sensitive financial data.

Lp3

Medium
Category
MCP Least Privilege
Confidence
81% confidence
Finding
The skill describes code usage and CLI execution that inherently requires network access and may access environment configuration, but it does not declare any explicit tool scope such as allowed-tools or permissions. This creates an authorization and review gap: consumers cannot easily tell what capabilities the skill expects, and an agent/runtime may grant broader access than intended.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
Using npx with an unpinned package name causes the latest published package version to be fetched and executed at runtime, which introduces a supply-chain risk. If the package is compromised, typo-squatted, or updated with malicious code, users invoking the documented command could execute attacker-controlled code on their system.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
This second npx example has the same unpinned execution risk: it may download and run whatever version is current at invocation time. In security-sensitive environments, that creates a straightforward path for supply-chain compromise through malicious upstream publication or account takeover.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
src/index.js:10