Back to skill

Security audit

Yfinance

Security checks for vulnerabilities and agentic risk

Overview

This stock-data skill is mostly coherent, but it can automatically start an unauthenticated FastAPI service exposed on all network interfaces and documents optional persistent systemd deployment.

Install only if you are comfortable running a local market-data web service. Prefer binding it to 127.0.0.1, avoid --reload for normal use, do not expose port 8000 publicly without authentication and rate limits, and treat the systemd instructions as optional deployment guidance requiring separate hardening.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:40
Finding
Unauthenticated Development Server Exposed on All Network Interfaces<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:40`; `README.md:63` **Vulnerability Type**: Exposed development service with no access control **Risk Level**: Medium ### Complete Code Snippet `SKILL.md:40`: ```bash curl http://localhost:8000/ || (cd ~/.openclaw/workspace/skills/yfinance && uvicorn main:app --host 0.0.0.0 --port 8000 --reload &) ``` `README.md:63`: ```bash uvicorn main:app --host 0.0.0.0 --port 8000 --reload ``` ### Technical Analysis The documented startup procedure binds Uvicorn to `0.0.0.0`, making the service reachable through every available network interface rather than only through localhost. It also enables `--reload`, which is a development feature that monitors the source tree and restarts the application when files change. The application implements no authentication, authorization, request throttling, or concurrency controls. All API callers can invoke operations that generate outbound Yahoo Finance requests and process potentially large historical datasets. This configuration exceeds the minimum network privileges required by the declared Skill functionality because `SKILL.md` and `openapi.json` otherwise use `http://localhost:8000`. Although no direct remote-code-execution path was identified, exposing a development server unnecessarily expands the reachable attack surface. ### Attack Path 1. A user starts the Skill using the documented command. 2. Uvicorn listens on port 8000 on every network interface. 3. A remote party that can route traffic to the host discovers the open port. 4. The party repeatedly invokes endpoints such as `/history`, `/fundamentals`, or `/price`. 5. Each request causes local processing and outbound requests through `yfinance`. 6. Sustained requests consume host resources and Yahoo Finance rate limits, potentially degrading or denying service to legitimate users. ### Impact Assessment An attacker does not obtain operating-system privileges from this issue alone. However, a network ...[truncated 310 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Bind the default server to localhost: ```bash uvicorn main:app --host 127.0.0.1 --port 8000 ``` - Remove `--reload` from all ordinary and production startup instructions. - If remote access is required, place the service behind an authenticated reverse proxy with TLS. - Restrict inbound traffic through host and cloud firewalls to explicitly trusted clients. - Add request rate limits, concurrency limits, timeouts, and response-size limits. - Validate ticker lengths and allow only documented values for `period` and `interval`. - Clearly separate local-development instructions from hardened remote-deployment instructions. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
main.py:22
Finding
Wildcard Cross-Origin Resource Sharing Policy<![CDATA[ ## Vulnerability Details **File Location**: `main.py:22-27` **Vulnerability Type**: Unrestricted cross-origin API access **Risk Level**: Low ### Complete Code Snippet ```python app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) ``` ### Technical Analysis The CORS middleware permits every web origin, every HTTP method, and every request header. The declared connector does not require arbitrary browser origins because its normal client communicates with a localhost API. CORS is not itself a network firewall, but this policy removes browser-origin isolation for the service. When combined with the all-interface listener, or with a browser able to reach localhost, an attacker-controlled website can programmatically interact with the API and read its responses. The current API does not expose credentials or state-changing functions, which limits confidentiality and integrity impact. Nevertheless, unrestricted cross-origin access makes browser-driven resource abuse easier and is broader than necessary. ### Attack Path 1. The FastAPI service is running on port 8000. 2. A user visits an attacker-controlled webpage. 3. JavaScript on that page sends cross-origin requests to the service. 4. The wildcard CORS configuration authorizes the origin and permits response access. 5. The page repeatedly calls data-intensive endpoints. 6. The local service performs the corresponding processing and outbound Yahoo Finance requests. ### Impact Assessment No operating-system or account privileges are gained. The principal impact is unauthorized use of the API through a victim's browser, including resource consumption, upstream rate-limit exhaustion, and reconnaissance of service responses. The scope is limited to the unauthenticated market-data API and its available resources. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Remove `CORSMiddleware` entirely if browser clients are not required. - Otherwise, replace the wildcard origin with an explicit allowlist: ```python app.add_middleware( CORSMiddleware, allow_origins=["https://trusted.example"], allow_methods=["GET"], allow_headers=["Accept", "Content-Type"], ) ``` - Do not treat CORS as authentication; require a separate authentication mechanism for remotely accessible deployments. - Bind the service to `127.0.0.1` when it is intended only for local Agent use. - Add rate limiting and request-concurrency controls. ]]>

T06 · System Persistence

Warning
Location
README.md:194
Finding
Privileged Installation of a Persistent Public-Facing Service<![CDATA[ ## Vulnerability Details **File Location**: `README.md:194-216` **Vulnerability Type**: Boot persistence through systemd **Risk Level**: Medium ### Complete Code Snippet ```bash sudo nano /etc/systemd/system/yfinance.service ``` ```ini [Unit] Description=YFinance FastAPI Server After=network.target [Service] User=azureuser WorkingDirectory=/home/azureuser/yfinance-connector ExecStart=uvicorn main:app --host 0.0.0.0 --port 8000 Restart=always [Install] WantedBy=multi-user.target ``` ```bash sudo systemctl enable yfinance sudo systemctl start yfinance sudo systemctl status yfinance ``` ### Technical Analysis The README instructs users to employ `sudo` to create and enable a systemd service. The service is configured to start during normal multi-user boot and restart continuously after failure. It also listens on all network interfaces. This mechanism is transparently documented as optional Azure deployment guidance and is related to the stated purpose of keeping the API available. It is not evidence of a hidden backdoor. Nevertheless, it goes beyond the privileges required for ordinary local Skill execution and turns an unauthenticated network listener into a cross-session service. The service runs as `azureuser`, not as root, which reduces direct privilege impact. However, the instructions contain no systemd sandboxing, filesystem protections, environment isolation, authentication, or firewall requirements. If the working directory or executable resolution can be modified by another local principal, the persistent service could subsequently execute altered application code as `azureuser`. ### Attack Path Remote availability-abuse path: 1. An administrator follows the README and creates the service with `sudo`. 2. `systemctl enable` registers it to start automatically at boot. 3. The service listens on all network interfaces and restarts after failures. 4. A network-reachable attacker repeatedly invokes the unauthenticated endpoints. 5. Rebo ...[truncated 1014 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - State explicitly that systemd installation is optional and unnecessary for normal local Skill use. - Bind to `127.0.0.1` unless remote access is an explicit requirement. - Use a dedicated, non-login service account with no administrative privileges. - Place application files in a root-owned, non-user-writable deployment directory. - Use an absolute executable path from a controlled virtual environment. - Add systemd hardening directives, for example: ```ini NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=true ProtectKernelTunables=true ProtectControlGroups=true RestrictSUIDSGID=true RestrictAddressFamilies=AF_INET AF_INET6 ``` - Add authentication, TLS termination, firewall restrictions, rate limits, and monitoring before allowing remote access. - Use an explicit operational removal procedure: ```bash sudo systemctl disable --now yfinance sudo rm /etc/systemd/system/yfinance.service sudo systemctl daemon-reload ``` ]]>

T09 · Insecure Skill Coding Practices

Note
Location
main.py:128
Finding
Raw Internal Exceptions Returned to Unauthenticated Clients<![CDATA[ ## Vulnerability Details **File Location**: `main.py:128`, `main.py:174`, `main.py:254`, `main.py:286`, `main.py:316` **Vulnerability Type**: Internal error information disclosure **Risk Level**: Low ### Complete Code Snippet The following handler is repeated in the price, history, fundamentals, dividends, and splits routes: ```python except Exception as e: raise HTTPException(status_code=500, detail=str(e)) ``` The history endpoint additionally preserves intentional HTTP errors before exposing all other exceptions: ```python except HTTPException: raise except Exception as e: raise HTTPException(status_code=500, detail=str(e)) ``` ### Technical Analysis The endpoints convert arbitrary exception messages directly into HTTP response bodies. Messages generated by FastAPI dependencies, pandas, `yfinance`, networking libraries, or malformed upstream data may reveal implementation details and operational state. No evidence shows that current exception strings contain secrets, and stack traces are not directly returned by this code. The vulnerability is therefore limited to message-level information disclosure. It can still assist reconnaissance by exposing dependency behavior, unsupported input details, and upstream failures. The lack of strict ticker, period, and interval allowlists gives a remote caller additional opportunities to deliberately trigger distinct errors. ### Attack Path 1. An attacker sends malformed, unsupported, unusually long, or edge-case ticker and history parameters. 2. `yfinance`, pandas, formatting logic, or an upstream request raises an exception. 3. The route catches the exception. 4. `str(e)` is inserted into the unauthenticated HTTP 500 response. 5. The attacker compares responses to identify internal behavior and refine further requests. ### Impact Assessment The issue does not directly grant additional privileges or code execution. Its impact is reconnaissance and potential disclosure of dependency, upst ...[truncated 82 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Log complete exception details only on the server. - Return a stable generic response to clients: ```python import logging logger = logging.getLogger(__name__) except Exception: logger.exception("Yahoo Finance request failed") raise HTTPException( status_code=502, detail="Unable to retrieve market data", ) ``` - Validate ticker syntax and impose a conservative maximum length. - Define enumerations or allowlists for `period` and `interval`. - Use structured internal error identifiers for troubleshooting without exposing raw exception messages. - Ensure production logging does not record secrets or unnecessary user-supplied data. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Non-Reproducible Dependency Resolution Using Unbounded Minimum Versions<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-4` **Vulnerability Type**: Uncontrolled third-party dependency updates **Risk Level**: Low ### Complete Code Snippet ```text fastapi>=0.110.0 uvicorn[standard]>=0.29.0 yfinance>=0.2.40 pandas>=2.0.0 ``` ### Technical Analysis Every dependency is specified only with a minimum version. A future installation can therefore select any newer release accepted by the resolver. Builds performed at different times may install materially different code without changes to the audited project. The package names and sources shown in the project are consistent with the declared functionality. No typosquatting, dependency-confusion package name, malicious package, or nonstandard package repository was identified. The risk arises from non-reproducible resolution and automatic trust of future releases, rather than from a currently confirmed malicious dependency. Because Python packages execute code during installation and application runtime, a future compromised or unexpectedly incompatible release could affect the host when users follow the documented `pip install -r requirements.txt` instruction. ### Attack Path 1. A dependency publishes a future release that is compromised, vulnerable, or incompatible. 2. A user runs `pip install -r requirements.txt`. 3. The package resolver selects that later release because the requirement has no upper bound or exact pin. 4. Package installation or import executes the newly selected code. 5. The code runs with the privileges of the user performing installation or starting the service. This path is contingent on a future unsafe release; no current compromised version was established during the static audit. ### Impact Assessment The potential privilege level is that of the installation or service account. Under ordinary local installation this is the invoking user; under the documented systemd deployment, runtime dependency code executes as `azureuser`. If a ...[truncated 161 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin dependencies to reviewed exact versions. - Generate and commit a lock file containing cryptographic hashes. - Install with hash verification where supported, such as `pip install --require-hashes`. - Perform dependency updates through a controlled review and testing process. - Run vulnerability and license scanning against the resolved dependency graph. - Install into an isolated virtual environment as an unprivileged user. - Avoid using `sudo pip` or installing application dependencies into the system Python environment. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (17)

External Script Fetching

High
Category
Supply Chain
Content
Verify it is up:

```bash
curl http://localhost:8000/
```

## Indonesia Stock Tickers
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Possible Typosquatting: 'uvicorn' resembles popular package 'gunicorn'

High
Category
Supply Chain
Confidence
70% confidence
Finding
Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
### Keep alive with systemd

```bash
sudo nano /etc/systemd/system/yfinance.service
```

```ini
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
### Keep alive with systemd

```bash
sudo nano /etc/systemd/system/yfinance.service
```

```ini
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
### Keep alive with systemd

```bash
sudo nano /etc/systemd/system/yfinance.service
```

```ini
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
### Keep alive with systemd

```bash
sudo nano /etc/systemd/system/yfinance.service
```

```ini
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Session Persistence

Medium
Category
Rogue Agent
Content
```

```bash
sudo systemctl enable yfinance
sudo systemctl start yfinance
sudo systemctl status yfinance
```
Confidence
80% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill instructs the agent to start a long-running FastAPI/uvicorn server in the background to fulfill a simple data-fetching task. That expands the execution scope from one-shot retrieval into persistent local service management, increasing attack surface and enabling unintended exposure or abuse of a localhost HTTP service.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The rule states that if a request is in Bahasa Indonesia, the skill must respond in Bahasa. This is a locale/language behavior expressed as a hard requirement, and the file does not indicate that the user may choose another response language or opt in to this constraint.

Natural-Language Policy Violations

Low
Confidence
76% confidence
Finding
The module docstring says the connector is 'optimised for Indonesia stocks' and later code auto-appends the .JK suffix by default, which biases behavior toward a specific market/locale. For a general finance connector, this is a locale-specific constraint that is not presented as an explicit user choice in the top-level description.

Vague Triggers

Low
Confidence
81% confidence
Finding
This manifest file states that all tickers without a suffix are automatically treated as IDX stocks by appending .JK, which is a broad default behavior without clear exclusion cases. Because many stock symbols exist across markets, the description does not clearly define when auto-conversion should or should not occur, increasing the chance of unintended interpretation.

Unpinned Dependencies

Low
Category
Supply Chain
Content
fastapi>=0.110.0
uvicorn[standard]>=0.29.0
yfinance>=0.2.40
pandas>=2.0.0
Confidence
94% confidence
Finding
The dependency is specified with a lower bound only, which allows future installs to resolve to different FastAPI versions over time. This weakens build reproducibility and can unintentionally introduce vulnerable or breaking releases into the skill's runtime environment.

Unverifiable Dependency: fastapi has 3 known advisory(ies) (CVE-2021-32677 (Cross-Site Request Forgery (CSRF) in FastAPI); CVE-2021-32677 (FastAPI is a web framework for building APIs with Python 3.6+ based on standard ); CVE-2024-24762 (FastAPI is a web framework for building APIs with Python 3.8+ based on standard )), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
86% confidence
Finding
FastAPI has known advisories, and because the manifest does not pin a specific version, it is impossible to verify whether the deployed version is affected. In practice this creates avoidable exposure because installers may resolve to a vulnerable release depending on timing and environment.

Unverifiable Dependency: uvicorn has 4 known advisory(ies) (CVE-2020-7694 (Log injection in uvicorn); CVE-2020-7695 (HTTP response splitting in uvicorn); CVE-2020-7694 (This affects all versions of package uvicorn. The request logger provided by the) +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
84% confidence
Finding
Uvicorn has multiple historical advisories, but the open-ended requirement prevents determining whether the installed version contains fixes. This uncertainty is a supply-chain security weakness because server-facing packages can become exposed through vulnerable transitive or resolved versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
fastapi>=0.110.0
uvicorn[standard]>=0.29.0
yfinance>=0.2.40
pandas>=2.0.0
Confidence
94% confidence
Finding
Using yfinance>=0.2.40 without an upper bound or exact pin means deployments may consume newer releases that have not been tested or reviewed. This creates supply-chain and stability risk because behavior and security posture can change between installs.

Unpinned Dependencies

Low
Category
Supply Chain
Content
fastapi>=0.110.0
uvicorn[standard]>=0.29.0
yfinance>=0.2.40
pandas>=2.0.0
Confidence
94% confidence
Finding
An unpinned pandas requirement permits non-deterministic installs and may pull in versions with newly introduced flaws or incompatible behavior. For a data-processing skill, this can affect both reliability and the security reviewability of the deployed environment.

Unverifiable Dependency: pandas has 1 known advisory(ies) (CVE-2020-13091 (** DISPUTED ** pandas through 1.0.3 can unserialize and execute commands from an)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
79% confidence
Finding
Because pandas is not pinned, the project cannot demonstrate that it avoids versions associated with known advisories. Even if the current minimum is above some affected releases, the absence of exact version control leaves room for inconsistent and unverified installations.

Static analysis

No suspicious patterns detected.