Back to skill

Security audit

Stock Analysis

Security checks for vulnerabilities and agentic risk

Overview

The skill broadly matches its A-share analysis purpose, but it has review-worthy flaws that could expose an LLM API key to a caller-chosen endpoint and write reports outside the intended folder.

Install only in a trusted environment, and do not expose the handler to untrusted callers until configuration fields are allowlisted and LLM endpoints are restricted. Treat saved reports as local persistence, keep output paths under a known reports directory, pin dependencies, and assume market/news content and user prompts may be sent to configured LLM and search providers.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
src/index.py:180
Finding

Environment API Key Exfiltration Through a Caller-Controlled LLM Endpoint

Content
View full analysis
LLMClient: return LLMClient( base_url=config.llm_base_url, api_key=config.llm_api_key, model=config.llm_model, ) ``` ```python # src/index.py:180-183 output_dir = input.get("output_dir") config_overrides = { k: v for k, v in input.items() if k not in ("mode", "code", "save", "output_dir") } config = SkillConfig(**config_overrides) if config_overrides else None ``` ```python # src/config.py:31-33 llm_base_url: str = field( default_factory=lambda: os.getenv( "LLM_BASE_URL", "https://api.deepseek.com/v1" ) ) llm_api_key: str = field( default_factory=lambda: os.getenv("LLM_API_KEY", "") ) llm_model: str = field( default_factory=lambda: os.getenv("LLM_MODEL", "deepseek-chat") ) ``` ```python # src/llm/client.py:15-17 def __init__(self, base_url: str, api_key: str, model: str): self.client = AsyncOpenAI(base_url=base_url, api_key=api_key) self.model = model ``` ### Technical Analysis The public handler converts every input field other than four reserved fields into a `SkillConfig` constructor argument. This allows a caller to override `llm_base_url`, even though that field is not declared in the handler input schema. If the caller supplies `llm_base_url` but omits `llm_api_key`, the dataclass default factory automatically loads `LLM_API_KEY` from the process environment. The resulting configuration therefore combines an attacker-selected destination with a host-provided secret. `AsyncOpenAI` subsequently uses that secret when authenticating to the selected endpoint. Configuration validation only checks whether the endpoin ...[truncated 1506 chars]
Remediation
View remediation

T01 · Skill Instruction Hijacking

Error
Location
src/analyzer/stock.py:257
Finding

Indirect Prompt Injection Through Untrusted News Content

Content
View full analysis
10: date_str = date_str[:10] items.append(NewsItem( title=title, snippet=snippet, date=date_str, source=source, url="", info_type=info_type, content=content, )) ``` ```python # src/analyzer/stock.py:257-270 news_text = "暂无资讯数据" if news: limited = news[:5] lines = [] for i, item in enumerate(limited, 1): type_tag = { "report": "[研报]", "announcement": "[公告]" }.get(item.info_type, "[新闻]") source_tag = f" [{item.source}]" if item.source else "" text = item.content or item.snippet if text and len(text) > 20 ...[truncated 2454 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/report.py:393
Finding

Arbitrary Report File Placement Through Unvalidated Output Paths

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Unpinned Third-Party Dependencies Installed Without Integrity Verification

Content
View full analysis
=1.0.0 efinance>=0.5.0 akshare>=1.10.0 numpy>=1.24.0 pandas>=2.0.0 httpx>=0.25.0 requests>=2.28.0 python-dotenv>=1.0.0 ``` ```yaml # manifest.yaml:33-36 install: - kind: uv command: pip install -r requirements.txt ``` ```yaml # SKILL.md:40-43 install: - kind: uv command: pip install -r requirements.txt ``` ### Technical Analysis Every dependency is specified using only a lower version bound. Consequently, two installations performed at different times may resolve to substantially different package versions, including major releases that were never reviewed with this Skill. No lockfile, package hashes, trusted package index restriction, or reviewed transitive dependency set is present. Installation therefore depends on the current state of the configured Python package index and resolver. The audit did not identify a known malicious package among the listed names. The confirmed issue is the absence of version and integrity controls, not proof that a current dependency is malicious. ### Attack Path 1. The Skill installation command runs `pip install -r requirements.txt`. 2. The package resolver selects the newest versions satisfying each lower bound and resolves their transitive dependencies. 3. A compromised future release, compromised dependency account, malicious transitive package, or incompatible major version may satisfy these constraints. 4. Pip downloads and installs the selected artifacts without comparing them to repository-approved hashes. 5. Package installation hooks or imported package code execute with the installer or Skill runtime's privileges. ### Impact Assessment If an allowed direct or transitive package is compromised, malicious code ...[truncated 407 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (70)

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 · README.md (reported line 85)May include surrounding context.

2. 配置环境变量

bash
cp .env.example .env

编辑 .env 文件,填入你的 API Key:

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README says the skill can be used directly with phrases like "分析贵州茅台" and "市场分析" without documenting any stricter trigger scope, exclusion conditions, or invocation context. In a markdown skill description, such generic phrases are ambiguous enough to collide with normal discussion about stocks or markets and could cause unintended activation.

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 · README.md (reported line 165)May include surrounding context.

md
from src.config import SkillConfig

config = SkillConfig(
    llm_base_url="https://api.openai.com/v1",
    llm_api_key="sk-xxx",
    llm_model="gpt-4o",
)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger list includes broad generic phrases like '分析股票', '市场分析', 'stock analysis', and 'market analysis', which can cause the skill to activate for vague requests that may not require this tool. Over-broad triggering increases the chance of unintended invocation, unnecessary data access, and user confusion about when external APIs or report generation will occur.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The skill documents saving reports to disk, including custom output directories, but does not explicitly require informing the user before creating files. This can lead to unexpected local file creation, accidental persistence of potentially sensitive financial queries, or writing into user-specified paths without clear consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill states that full news/article content may be sent directly to an LLM for analysis, but it does not present an explicit privacy or data-handling warning. Even if news content is public, full-text transmission to external LLM providers can create licensing, compliance, and data-governance risks, especially when combined with user prompts, proprietary feeds, or provider logging.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This manifest/config example contains natural-language guidance exclusively in Chinese, including required/optional configuration notes and logging descriptions. That can violate a language/locale policy when users are not explicitly offered a language choice or told that the skill is region/language-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Natural-language text throughout the manifest is exclusively Chinese, including the main description and input/output field descriptions. There is no indication that the skill is intentionally limited to Chinese-speaking users or that alternate language support is unavailable by design.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The system prompt explicitly defines the assistant as an A-share securities analyst in Chinese, which effectively constrains responses to Chinese. Under the policy, a fixed language/locale requirement is a finding unless the skill offers user opt-in or clearly documents a justified region-specific constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The prompt content is entirely in Chinese and directs the model to analyze A-share stocks in that language, but the file does not provide an explicit language choice mechanism. This can violate the language/locale policy unless the locale restriction is clearly justified and documented.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This prompt defines a Chinese-language A-share market analyst role and output structure without offering an alternative language or explicit user consent. The policy permits locale constraints only when users can choose or the regional limitation is clearly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The code's user-facing natural-language strings, comments, and logging are consistently in Chinese, and the stock-analysis flow appears designed around Chinese-language prompts and outputs without exposing any locale selection. Under the policy, forcing a specific language without user opt-in is a locale/language policy concern unless the constraint is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The analyzer builds a prompt containing stock metadata, realtime quote data, financial data, capital flow data, and news text, then sends it to self.llm.analyze_json(...). Although there is internal logging, there is no confirmation prompt, print/message to the user, or explanatory comment/docstring here disclosing that collected data will be transmitted to an LLM service.

Content

No source excerpt is available for this finding.

Ssd 1

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

Untrusted news titles/content/snippets are concatenated directly into the LLM user prompt without isolation or sanitization. Malicious or malformed article text can inject instructions such as overriding analysis criteria, fabricating conclusions, or biasing investment recommendations, causing the model to follow attacker-controlled semantic input rather than the intended analysis task.

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 · README.md (reported line 92)May include surrounding context.

md
@dataclass
class SkillConfig:
    llm_base_url: str = field(default_factory=lambda: os.getenv("LLM_BASE_URL", "https://api.deepseek.com/v1"))
    llm_api_key: str = field(default_factory=lambda: os.getenv("LLM_API_KEY", ""))
    llm_model: str = field(default_factory=lambda: os.getenv("LLM_MODEL", "deepseek-chat"))

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 · README.md (reported line 298)May include surrounding context.

md
@dataclass
class SkillConfig:
    llm_base_url: str = field(default_factory=lambda: os.getenv("LLM_BASE_URL", "https://api.deepseek.com/v1"))
    llm_api_key: str = field(default_factory=lambda: os.getenv("LLM_API_KEY", ""))
    llm_model: str = field(default_factory=lambda: os.getenv("LLM_MODEL", "deepseek-chat"))

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 · config.example.yaml (reported line 2)May include surrounding context.

yaml
@dataclass
class SkillConfig:
    llm_base_url: str = field(default_factory=lambda: os.getenv("LLM_BASE_URL", "https://api.deepseek.com/v1"))
    llm_api_key: str = field(default_factory=lambda: os.getenv("LLM_API_KEY", ""))
    llm_model: str = field(default_factory=lambda: os.getenv("LLM_MODEL", "deepseek-chat"))

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 · manifest.yaml (reported line 41)May include surrounding context.

yaml
@dataclass
class SkillConfig:
    llm_base_url: str = field(default_factory=lambda: os.getenv("LLM_BASE_URL", "https://api.deepseek.com/v1"))
    llm_api_key: str = field(default_factory=lambda: os.getenv("LLM_API_KEY", ""))
    llm_model: str = field(default_factory=lambda: os.getenv("LLM_MODEL", "deepseek-chat"))

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 · src/config.py (reported line 31)May include surrounding context.

python
@dataclass
class SkillConfig:
    llm_base_url: str = field(default_factory=lambda: os.getenv("LLM_BASE_URL", "https://api.deepseek.com/v1"))
    llm_api_key: str = field(default_factory=lambda: os.getenv("LLM_API_KEY", ""))
    llm_model: str = field(default_factory=lambda: os.getenv("LLM_MODEL", "deepseek-chat"))

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This Python file contains many natural-language log strings exclusively in Chinese, such as status and error messages. Because the rule applies to all file types and there is no indication of user opt-in or a documented region-specific locale requirement in this file, the implementation appears to enforce a specific language implicitly.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The file’s natural-language docstrings and disclaimer strings are written exclusively in Chinese throughout, indicating a fixed language/locale behavior. Under the policy, forcing a specific language without user opt-in or clear justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code embeds Chinese labels, status strings, titles, and formatting throughout the generated reports, which forces a specific language/locale in user-facing output. The file provides no opt-in, configuration, or documentation indicating that the skill is intentionally limited to Chinese-speaking users or a China-specific deployment context.

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 · src/search/bocha.py (reported line 18)May include surrounding context.

python
def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = "https://api.bochaai.com/v1/web-search"

    @property
    def name(self) -> str:

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 · src/search/brave.py (reported line 18)May include surrounding context.

python
def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = "https://api.search.brave.com/res/v1/news/search"

    @property
    def name(self) -> str:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The request hard-codes "hl": "zh-cn" and "gl": "cn", which forces Chinese language and China geolocation settings for all searches. This is a natural-language locale constraint with no visible user choice or justification in the file.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.