T09 · Insecure Skill Coding Practices
- Location
skill-entry.js:2- Finding
Reusable API Key Stored in Plaintext Without Explicit Access Restrictions
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill largely matches stock watchlist management, but it needs Review because it stores reusable credentials in plaintext and exposes broader authenticated gateway access than the stated watchlist task requires.
Install only if you trust this publisher and the local machine. Expect the skill to collect device information, store an API key in a shared local JSON file, contact GTJA/GTHHT gateway services, and read or change your 'My Watchlist' stock list. Avoid using it in shared or untrusted environments, and be careful with any flow that asks you to paste or send a reusable API key.
skill-entry.js:2Reusable API Key Stored in Plaintext Without Explicit Access Restrictions
skill-entry.js:5Configurable Gateway URLs Can Redirect Authentication Headers and Device Identifiers
The documented purpose is limited watchlist management, but the described behavior includes authorization persistence, JWT/user-identifier handling, generic MCP client usage, gateway config management, and name/code mapping utilities. This mismatch is dangerous because reviewers and users may trust the skill with a narrow mental model while it actually has broader data access and execution pathways, which can conceal sensitive-token handling and enable unintended operations if the generic client is abused.
The authorization flow explicitly instructs the user to create or copy an active API key and send it back to complete setup, normalizing direct credential disclosure to the skill/operator. Asking users to reveal reusable secrets is highly dangerous because it enables account compromise, replay, and unauthorized access well beyond the narrow watchlist function.
The included MCP client can invoke arbitrary gateways/tools, not just watchlist operations, and the code only blocks one specific optionalStock mutation path while still allowing broad access to market, info, yaowen, hotTopic, mqtt, and other configured endpoints. This violates least privilege and could let the skill act as a general-purpose privileged RPC proxy if an attacker or prompt injection causes those paths to be used.
The skill advertises executable commands and MCP/environment-backed behavior but does not declare any explicit tool scope such as allowed-tools or permissions. That creates a least-privilege failure: an agent or platform may permit broader tool access than users or reviewers expect, increasing the blast radius of prompt injection or misuse within a finance-related skill that can alter watchlists and persist authorization state.
The trigger rules state that all watchlist-related requests must use this skill, with broad keywords and no clear exclusions. Over-broad mandatory routing can cause the agent to invoke a state-changing financial skill in loosely related conversations, increasing the chance of unintended authorization flows, unnecessary data access, or accidental edits when user intent is ambiguous.
The manifest exposes finance-related tools using broad descriptions and permissive invocation examples, but it does not define clear activation boundaries, preconditions, or user-intent checks. In an agent setting, this can cause the skill to be selected for ambiguous requests and can lead to unintended access to portfolio/watchlist data or unintended execution of market and account-related actions.
The skill exposes a state-changing watchlist operation tool that can add or remove securities, but the manifest provides no warning, confirmation requirement, or safety guidance for destructive actions. Because this skill manages a user's financial watchlist, an accidental or prompt-induced remove operation could silently alter user preferences and trading workflow, making the context more sensitive than a generic content-management action.
The skill bundles a full authorization subsystem that generates auth links, polls for credentials, extracts tokens, and persists API keys to disk, which goes well beyond the declared watchlist-only scope. In a skill that should merely manage a user's watchlist, embedded credential acquisition/storage materially expands the attack surface and creates opportunities for credential misuse, theft, or reuse outside the intended function.
The code writes the API key directly to a JSON file on disk via writeFileSync, and the surrounding implementation indicates ordinary filesystem storage rather than a protected secret store. Persisting long-lived credentials in plaintext on disk increases the risk of local theft, accidental inclusion in backups, leakage through logs/support bundles, or reuse by other processes on the host.
The skill's natural-language output and CLI guidance are hardcoded in Chinese throughout the file, with no apparent user opt-in or locale selection. This can violate language/locale policy when a skill forces a specific language rather than offering a choice or documenting a justified region-specific constraint.
Examples such as '帮我查询下我的自选股?' and '查一下自选股行情' are natural conversational phrases rather than tightly scoped invocation conditions. Because the document does not pair these examples with non-trigger examples or stricter activation rules, they may encourage unintended invocation from routine discussion.
The manifest claims support for querying watchlist quotes and adding/removing watchlist stocks, but the code also exposes a separate 'stockMap' CLI module for code/name lookups and stats. This is ancillary utility functionality that is not disclosed in the skill description and is not itself a watchlist-management action.