Back to skill

Security audit

Stock Quote

Security checks for vulnerabilities and agentic risk

Overview

This stock-quote skill is a straightforward Yahoo Finance quote helper with ordinary network and dependency risks, but no hidden persistence, credential access, destructive behavior, or purpose mismatch.

Install only if you are comfortable with requested ticker symbols being sent to Yahoo Finance and with uv resolving the Python dependencies at runtime. For stronger safety, pin dependency versions and escape ticker and remote metadata before rendering Rich markup.

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)

T08 · Insecure Dependencies

Warning
Location
scripts/quote.py:1
Finding
Unpinned Runtime Dependencies Enable Supply-Chain Exposure<![CDATA[ ## Vulnerability Details **File Location**: `scripts/quote.py:1-3` **Vulnerability Type**: Unpinned third-party dependencies **Risk Level**: Medium ### Vulnerable Code ```python # /// script # dependencies = ["rich", "httpx"] # /// ``` ### Technical Analysis The script declares `rich` and `httpx` without exact versions or integrity constraints. When the documented `uv run scripts/quote.py` command is executed in an environment where these packages are not already resolved and locked, `uv` can retrieve whichever compatible releases are currently available from the configured package index. Because both packages are imported and executed by the script, a compromised upstream release, package-index compromise, dependency-resolution attack, or unexpectedly unsafe future version could introduce code that runs with the privileges of the user invoking the Skill. The reviewed code does not provide a lockfile, hashes, or another mechanism that binds execution to previously reviewed dependency artifacts. ### Attack Path 1. An attacker compromises an upstream dependency release, its publisher account, the configured package index, or the dependency-resolution environment. 2. A user runs the documented command: ```bash uv run scripts/quote.py AAPL ``` 3. `uv` resolves and downloads the mutable, unpinned dependency version. 4. Python imports `httpx` and `rich` before processing the requested ticker. 5. Malicious package initialization code executes in the Skill process. ### Impact Assessment Successful exploitation would execute code with the operating-system privileges of the user or Agent running the Skill. Depending on the execution environment, this could permit access to readable files, environment variables, network resources, and writable project or user files. The project does not explicitly request elevated privileges, so this finding does not independently provide root or administrator access. The practical scope is limited by the per ...[truncated 67 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin every direct dependency to an exact, reviewed version, for example: ```python # /// script # dependencies = [ # "rich==<reviewed-version>", # "httpx==<reviewed-version>", # ] # /// ``` 2. Prefer a locked project environment that records the full transitive dependency graph. 3. Verify downloaded artifacts with cryptographic hashes where the deployment workflow supports hash-locked requirements. 4. Configure package installation to use a trusted, authenticated package index. 5. Perform dependency updates through an explicit review and testing process rather than resolving new versions during normal Skill execution. 6. Run the Skill with least privilege and restrict filesystem and network access to reduce the impact of a compromised package. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/quote.py:140
Finding
Unescaped Ticker and Remote Metadata Are Interpreted as Rich Markup<![CDATA[ ## Vulnerability Details **File Locations**: `scripts/quote.py:140-149`, `scripts/quote.py:189-207`, and `scripts/quote.py:224-229` **Vulnerability Type**: Terminal markup injection **Risk Level**: Low ### Vulnerable Code Single-quote output constructs Rich markup using unescaped ticker and remotely supplied metadata: ```python price_str = fmt_price(current) header = f"[bold]{name} ({ticker})[/bold] [dim]{exchange}[/dim]" price_line = f"[bold white]{price_str}[/bold white] {change_str} {state_label}" # 52W range bar bar = build_52w_bar(current, week52_low, week52_high) range_line = f"52W {fmt_price(week52_low)} [dim]{bar}[/dim] {fmt_price(week52_high)}" vol_str = fmt_number(volume, prefix="") avg_vol_str = fmt_number(avg_volume, prefix="") vol_line = f"Volume {vol_str} [dim](avg {avg_vol_str})[/dim]" cap_line = f"Market Cap {fmt_number(mkt_cap)}" body = Text.from_markup( f"{price_line}\n\n{range_line}\n{vol_line}\n{cap_line}" ) console.print(Panel(body, title=Text.from_markup(header), expand=False)) ``` The comparison table also receives unescaped ticker and name strings: ```python for t in tickers: data = quotes.get(t) if data is None: table.add_row(t, "[red]Not found[/red]", "-", "-", "-", "-", "-") continue p = data["price"] s = data["summary"] name = (p.get("shortName") or p.get("longName") or t)[:28] current = get_raw(p, "regularMarketPrice") change = get_raw(p, "regularMarketChange") change_pct = get_raw(p, "regularMarketChangePercent") mkt_cap = get_raw(p, "marketCap") market_state = p.get("marketState", "") color = "green" if (change or 0) >= 0 else "red" arrow = "▲" if (change or 0) >= 0 else "▼" price_cell = fmt_price(current) change_cell = f"[{color}]{arrow} {fmt_price(abs(change or 0))}[/{color}]" pct_cell = f"[{color}]{(change_pct or 0)*100:+.2f}%[/{color}]" cap_cell = fmt_number(mkt_cap) if market_state == "REGULAR": statu ...[truncated 2245 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Escape every user-controlled or remotely supplied string before including it in Rich markup: ```python from rich.markup import escape safe_ticker = escape(ticker) safe_name = escape(str(name)) safe_exchange = escape(str(exchange)) header = ( f"[bold]{safe_name} ({safe_ticker})[/bold] " f"[dim]{safe_exchange}[/dim]" ) ``` 2. Escape ticker values in error messages: ```python console.print( f"[red]Ticker {escape(ticker)} not found or could not be fetched.[/red]" ) ``` 3. For table cells that do not require styling, construct `Text` objects with literal text or otherwise disable markup interpretation. 4. Keep trusted application-generated markup separate from untrusted data rather than building both through one formatted string. 5. Optionally validate ticker syntax against the expected Yahoo Finance symbol character set and reject control characters, brackets, and unexpected whitespace. Validation should supplement, not replace, output escaping. 6. Add tests using bracket-bearing ticker values and metadata to verify that they are displayed literally. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill appears to require network access to fetch Yahoo Finance data, but it does not declare any explicit tool scope or permissions. This creates a least-privilege and transparency problem: the runtime may grant broader capabilities than users or policy reviewers expect, making network-enabled behavior harder to audit and constrain.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The phrases "Is the market up today?" and "How's the market doing?" are broad, natural conversational questions that could match everyday discussion rather than a clearly scoped skill invocation. The file does not provide exclusion conditions or context boundaries to distinguish when these should activate the skill versus remain ordinary chat.

Missing User Warnings

Low
Confidence
89% confidence
Finding
This code sends command-line input to an external service via HTTP, which is a data-transmitting network operation covered by the warning requirement for code files. Although the script's purpose is to fetch quotes, there is no visible comment, prompt, or user-facing disclosure that entered ticker symbols will be sent to Yahoo Finance.

Static analysis

No suspicious patterns detected.