Back to skill

Security audit

quantum-portfolio-yand

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed local portfolio-optimization demo, but users should treat its dependency and input-size controls as research-grade rather than hardened.

Install in a virtual environment, prefer pinned or locked dependency versions, and avoid running it on untrusted or very large CSVs unless you add resource limits. Expect it to create or overwrite generated PNGs in assets/.

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 (3)

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Unpinned Third-Party Dependencies Create Supply-Chain Exposure

Content
View full analysis
=1.23 pandas>=1.5 scipy>=1.10 matplotlib>=3.6 dimod>=0.12 dwave-neal>=0.6,<0.7 ``` `README.md:50-51`: ```bash pip install -r requirements.txt python scripts/run_pipeline.py ``` `examples/demo_synthetic.md:7-8`: ```bash pip install -r requirements.txt # or: pip install dimod dwave-neal numpy pandas scipy matplotlib python scripts/run_pipeline.py ``` ### Technical Analysis The installation instructions direct users to install packages using broad version constraints. Except for the major-version upper bound on `dwave-neal`, these constraints allow future package releases to be selected without additional review. No lock file, package hashes, or trusted-index restrictions are provided. Python package installation may run package build or installation logic with the privileges of the invoking user. Consequently, compromise of an allowed upstream release, package-index account, or configured package source could turn the documented installation step into a code-execution channel. Mutable dependency resolution can also introduce incompatible releases that change numerical behavior without corresponding changes to this repository. This finding does not establish that any currently listed package is malicious. It identifies an avoidable supply-chain trust boundary created by installing unresolved future versions. ### Attack Path 1. An attacker compromises an allowed dependency release, its publisher account, or a package source configured in the target environment. 2. The attacker publishes a version satisfying one of the broad constraints. 3. A user follows the documented `pip install -r requirements.txt` command. 4. The resolver selects ...[truncated 879 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run_pipeline.py:171
Finding

Unbounded User-Controlled Work Parameters Permit Resource Exhaustion

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/data_loader.py:48
Finding

CSV Input Lacks Dimension and Finite-Value Validation

Content
View full analysis
tuple[np.ndarray, list[str]]: """Load user CSV. First col may be a date; remaining cols are tickers (returns).""" df = pd.read_csv(path) # Detect/drop date column first_col = df.columns[0] try: pd.to_datetime(df[first_col]) df = df.drop(columns=[first_col]) except (ValueError, TypeError): pass # Drop NaN rows; warn if too many n_before = len(df) df = df.dropna() if len(df) < 0.9 * n_before: print(f"[WARN] Dropped {n_before - len(df)}/{n_before} rows due to NaN.") # Validate numeric if not all(np.issubdtype(df[c].dtype, np.number) for c in df.columns): raise ValueError("All non-date columns must be numeric returns.") R = df.to_numpy(dtype=np.float64) # Sanity: looks-like-returns check (V1) if R.std() > 1.0 or (R.min() > 0.0 and R.mean() > 0.5): raise ValueError( "Input looks like prices, not returns. " "Pass R = prices.pct_change().dropna()." ) return R, list(df.columns) ``` ### Technical Analysis The loader reads the complete CSV before checking its shape and does not enforce the documented requirements that the return matrix have at least 60 rows and between 2 and 500 columns. It also does not reject positive or negative infinity through `np.isfinite`. An oversized CSV can therefore consume substantial memory during parsing and trigger further expensive covariance, optimization, and dense QUBO operations. Infinite values are numeric and are not removed by `dropna()`. They can propagate into covariance and eigenvalue calculations, causing exceptions, non-finite solver state, or prolonged numerical processing. The file path is explicitly supplied through `--csv` ...[truncated 1286 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (15)

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill explicitly states that running the pipeline produces figures into assets/, but it does not clearly warn the user that invocation will modify the local filesystem. While this is not inherently malicious, undisclosed write behavior can surprise users, overwrite prior outputs, or violate expectations in constrained or read-only environments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This markdown file explicitly states that the pipeline will save four figures into assets/, which is a filesystem write operation. The description does not warn whether existing files may be overwritten or that running the command will modify the working directory.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

L106 says to pin dwave-neal in dependencies and then separately notes that exact reproducibility additionally requires saving sampleset.record. This creates a documentation-level contradiction if pinning is read as the fix for reproducibility, while the sentence itself acknowledges pinning alone is insufficient for exact reproducibility.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

The dependency is specified with only a lower bound, which makes builds non-reproducible and can allow installation of unexpectedly vulnerable or incompatible future releases. In a requirements file, this is a real supply-chain hardening weakness even if it is not an immediately exploitable code flaw by itself.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
numpy>=1.23
pandas>=1.5
scipy>=1.10
matplotlib>=3.6

Unverifiable Dependency: numpy has 16 known advisory(ies) (CVE-2014-1859 (Numpy arbitrary file write via symlink attack); CVE-2021-41495 (NumPy NULL Pointer Dereference); CVE-2021-33430 (NumPy Buffer Overflow (Disputed)) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
88% confidence
Finding

Because numpy is not pinned, it is impossible to determine from this manifest whether installation will select a release affected by one of the known advisories. The danger here is uncertainty: the environment may resolve to a vulnerable version without review, especially in fresh or automated installs.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

Using an unpinned pandas version permits drift across environments and leaves the resolved package version dependent on install time and index state. That increases supply-chain risk and makes it harder to verify whether a vulnerable release is being installed.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
numpy>=1.23
pandas>=1.5
scipy>=1.10
matplotlib>=3.6
dimod>=0.12

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
84% confidence
Finding

The pandas advisory cannot be ruled out because the dependency is not fixed to a known-safe release. This creates a verifiable supply-chain hygiene issue even though the file alone does not prove a vulnerable version will always be installed.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

A minimum-only scipy constraint allows any later version to satisfy installation, including releases with newly introduced security or stability issues. This weakens reproducibility and complicates assurance of what code will actually be executed.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
numpy>=1.23
pandas>=1.5
scipy>=1.10
matplotlib>=3.6
dimod>=0.12
dwave-neal>=0.6,<0.7

Unverifiable Dependency: scipy has 4 known advisory(ies) (CVE-2013-4251 (SciPy creates insecure temporary directories); CVE-2013-4251 (The scipy.weave component in SciPy before 0.12.1 creates insecure temporary dire); CVE-2023-25399 (A refcounting issue which leads to potential memory leak was discovered in scipy) +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
87% confidence
Finding

Without a pinned scipy version, the project cannot demonstrate that it avoids known vulnerable releases. This uncertainty is dangerous in automated deployments because dependency resolution may change over time and silently introduce affected builds.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

An unpinned matplotlib dependency can resolve to different versions over time, creating avoidable supply-chain and reproducibility risk. While not directly exploitable on its own, it undermines secure build practices and can pull in vulnerable transitive code.

Content

Scanner excerpt · requirements.txt (reported line 4)May include surrounding context.

text
numpy>=1.23
pandas>=1.5
scipy>=1.10
matplotlib>=3.6
dimod>=0.12
dwave-neal>=0.6,<0.7

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

The dimod requirement is not fully pinned, so installations may consume different releases over time. That makes dependency provenance and vulnerability verification harder and increases exposure to unexpected package behavior.

Content

Scanner excerpt · requirements.txt (reported line 5)May include surrounding context.

text
pandas>=1.5
scipy>=1.10
matplotlib>=3.6
dimod>=0.12
dwave-neal>=0.6,<0.7

Static analysis

No suspicious patterns detected.