Back to skill

Security audit

modern-portfolio-theory

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its portfolio-management purpose, but its delete command can be abused to remove folders outside the portfolio area.

Review before installing. Use only in an isolated virtual environment as an unprivileged user, do not run delete with untrusted or path-like portfolio names, avoid --force unless you have verified the exact resolved directory, keep SMTP secrets in environment variables rather than plaintext config, and only add cron entries you can later inspect and remove.

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)

T09 · Insecure Skill Coding Practices

Error
Location
mpt_portfolio/cli.py:1007
Finding

Unvalidated Portfolio Name Allows Arbitrary Directory Deletion

Content
View full analysis
None: """Delete a portfolio and all its data.""" portfolio_dir = get_portfolios_dir() / portfolio if not portfolio_dir.exists(): console.print(f"[red]Error:[/red] Portfolio '{portfolio}' does not exist.") sys.exit(1) if not force: confirmed = Confirm.ask( f"Delete portfolio '{portfolio}' and all its data (config, state, reports)?", default=False, ) if not confirmed: console.print("[dim]Cancelled.[/dim]") return shutil.rmtree(portfolio_dir) console.print(f"[green]Portfolio '{portfolio}' deleted.[/green]") ``` ### Technical Analysis The `--portfolio` argument is joined directly to the portfolios directory and then passed to `shutil.rmtree()`. The command does not call the existing `validate_portfolio_name()` function and does not verify that the resolved target remains inside the intended portfolios directory. Because `pathlib.Path` does not remove or reject `..` components during path construction, an input containing traversal sequences can identify a directory outside `portfolios/`. The existence check does not provide a security boundary; it only confirms that the attacker-selected target exists. The `--force` option bypasses the interactive confirmation, allowing the destructive operation to execute immediately. This is a violation of filesystem path confinement and least-privilege expectations for a portfolio management operation. ### Attack Path 1. An attacker or untrusted automation supplies a traversal value as the portfolio name. 2. ...[truncated 1107 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Unpinned and Unverified Runtime Dependencies Create Supply-Chain Exposure

Content
View full analysis
=0.2.36 numpy>=1.24 pandas>=2.0 scipy>=1.11 matplotlib>=3.7 pyyaml>=6.0 rich>=13.0 click>=8.1 ``` Equivalent lower-bound-only constraints are also declared in `pyproject.toml:7-20`. The documented setup flow instructs users to install these dependencies with: ```bash pip install -r requirements.txt ``` ### Technical Analysis Every runtime dependency uses an open-ended lower-bound constraint. Consequently, installation can select any later version available from the configured package index. The project does not provide a reviewed lock file or hashes that bind installations to specific package artifacts. This makes builds non-reproducible and expands supply-chain risk. A future compromised release, maliciously replaced artifact, dependency-account takeover, or unsafe transitive dependency can be selected without any project change. Python package installation may execute build backend logic, and imported packages subsequently execute with the privileges of the user running the Skill. The dependency names observed in the manifests are consistent with the declared portfolio functionality; no typosquatted package was identified. The issue is the absence of version and artifact integrity controls rather than evidence that a currently listed package is malicious. ### Attack Path 1. A user follows the documented installation command: ```bash pip install -r requirements.txt ``` 2. The package resolver queries the configured Python package index. 3. Because only minimum versions are specified, it selects the newest compatible direct and transitive package releases. 4. If a selected release or artifact has been compromised, its installation or runtime code executes locally. 5. The malicious dependency inherits the installer or application ...[truncated 850 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (53)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The skill is described as a portfolio optimizer, but it also instructs environment verification, dependency installation guidance, and operational filesystem actions tied to scripts and config management. This is a meaningful behavior expansion beyond pure portfolio analysis, and users may not realize the skill can alter the local environment or operational setup.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill is described as a portfolio optimizer, but it also instructs environment verification, dependency installation guidance, and operational filesystem actions tied to scripts and config management. This is a meaningful behavior expansion beyond pure portfolio analysis, and users may not realize the skill can alter the local environment or operational setup.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill is described as a portfolio optimizer, but it also instructs environment verification, dependency installation guidance, and operational filesystem actions tied to scripts and config management. This is a meaningful behavior expansion beyond pure portfolio analysis, and users may not realize the skill can alter the local environment or operational setup.

Content

No source excerpt is available for this finding.

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · SKILL.md (reported line 193)May include surrounding context.

md
proceed until user replies.

If the user chooses weekly or monthly:
1. Update `portfolios/<name>/config.yaml` to set `monitoring.frequency` to the chosen value
2. Provide the cron line:

| Frequency | Cron Line |
|-----------|-----------|
| Weekly | `0 9 * * 1 scripts/cron_performance.sh <name>` |
| Monthly | `0 9 1-7 * 1-5 scripts/cron_performance.sh <name>` |

Tell the user to add this to their crontab alongside the rebalancing schedule. Like the rebalancing cron, **no LLM is involved** — it runs Python directly.

Regardless of choice, mention: "You can always generate a performance report on demand with `python -m mpt_portfolio performance -p <name>`"

---

## MODE 2: EXPLAIN RESULTS

When you run a CLI command or the user shows you output, explain it like this:

1. **2-3 plain-language sentences** summarizing what happened
2. Specifics only if the user asks

### Metrics reference

| Metric | What It Means | Good Value |
|--------|--------------|------------|
| Sharpe Ratio | Retu

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · mpt_portfolio/cli.py (reported line 1243)May include surrounding context.

python
month at 9am.",
        }
        perf_cron = perf_crons.get(monitoring_freq)
        if perf_cron:
            console.print(Panel(
                f"Performance monitoring: [bold]{monitoring_freq}[/bold]\n\n"
                f"Recommended cron schedule:\n"
                f"  [cyan]{perf_cron}[/cyan]\n\n"
                f"{perf_descs[monitoring_freq]}\n"
                f"Add this line to your crontab alongside the rebalancing schedule.",
                title="Performance Monitoring Schedule",
                border_style="green",
            ))


@main.command("list")
def list_portfolios() -> None:
    """List all portfolios."""
    portfolios_dir = get_portfolios_dir()
    portfolios = [d.name for d in portfolios_dir.iterdir() if d.is_dir() and (d / "config.yaml").exists()]

    if not portfolios:
        console.print("[yellow]No portfolios found. Run setup to create one.[/yellow]")
        return

    from rich.table import Table
    table = Table(title="Portfolios")
    table.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The invocation phrase is highly generic: a user saying "create a new portfolio" is ordinary conversational language that could unintentionally trigger this skill in a broader agent environment. In a multi-skill system, broad activation increases the chance of accidental execution of finance-related actions, including config creation and downstream portfolio operations.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · README.md (reported line 74)May include surrounding context.

See config/default.yaml for all options with comments.

nano portfolios/my-portfolio/config.yaml

3. Run optimization (automatically runs backtest + generates full report)

python -m mpt_portfolio opt -p my-portfolio

text

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 149)May include surrounding context.

See config/default.yaml for all options with comments.

nano portfolios/my-portfolio/config.yaml

3. Run optimization (automatically runs backtest + generates full report)

python -m mpt_portfolio opt -p my-portfolio

text

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

The recommendation to add a cron entry is a persistence mechanism: once configured, the skill's logic runs repeatedly without fresh user initiation. In finance tooling, recurring execution is more sensitive because it may emit notifications continuously and could evolve into operational trading-related workflows.

Content

Scanner excerpt · README.md (reported line 189)May include surrounding context.

Cron-Based Rebalancing

To automate rebalance checks, add a cron entry that runs the rebalance script:

bash

Session Persistence

Medium
Category
Rogue Agent
Confidence
88% confidence
Finding

Instructing users to install a cron job establishes persistent, recurring execution outside the immediate session. In an agent-skill context, persistence is security-relevant because it can cause ongoing autonomous checks, notifications, or later state-changing actions if paired with --execute or future config changes.

Content

Scanner excerpt · README.md (reported line 193)May include surrounding context.

script:

bash
crontab -e

# Example: check every Monday at 9:00 AM
0 9 * * 1 /path/to/modern-portfolio-theory/scripts/cron_rebalance.sh my-portfolio

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill requests shell, file read, file write, and environment capabilities but does not declare an explicit tool scope or permission boundary. That makes the effective authority of the skill unclear, increasing the chance that an agent will execute filesystem or shell actions the user did not anticipate.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill guides the user to create cron-based rebalancing without a strong warning that this introduces recurring scheduled execution with ongoing system and potentially financial effects. In context, scheduled portfolio rebalancing is more dangerous than ordinary automation because it can influence investment actions repeatedly after the initial setup.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
94% confidence
Finding

The skill instructs the user to edit crontab, creating persistence beyond the current session. Persistent scheduled execution increases risk because it continues operating after the user may have forgotten about it, and in this skill's context it can affect portfolio-management workflows and repeated data/report operations.

Content

Scanner excerpt · SKILL.md (reported line 161)May include surrounding context.

  1. The exact cron line to set up automated rebalancing:
bash
crontab -e
# Add the recommended cron line from the output

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The delete command is documented as a normal ongoing-management action without an explicit destructive-operation warning. In a portfolio-management context, deleting portfolio state may permanently remove configs, reports, and historical tracking data that users rely on for decisions or recordkeeping.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · mpt_portfolio/cli.py (reported line 317)May include surrounding context.

python
@click.option("--portfolio", "-p", required=True)
@click.option("--method", type=click.Choice(["max_sharpe", "min_variance", "efficient_frontier", "risk_parity"]))
@click.option("--save-state/--no-save-state", default=True)
@click.option("--auto-report/--no-auto-report", default=True, help="Automatically run backtest and generate full report")
def opt(portfolio: str, method: str | None, save_state: bool, auto_report: bool) -> None:
    """Run portfolio optimization and display results."""
    try:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

When --execute is supplied and rebalancing is needed, the command immediately applies portfolio changes via apply_rebalance without an interactive confirmation step or nearby user-facing warning about modifying stored portfolio state. Although the command name and flag imply action, this code path lacks the kind of explicit disclosure present in the delete command for a state-changing operation.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · mpt_portfolio/cli.py (reported line 1008)May include surrounding context.

python
@main.command()
@click.option("--portfolio", "-p", required=True)
@click.option("--force", is_flag=True, help="Skip confirmation prompt")
def delete(portfolio: str, force: bool) -> None:
    """Delete a portfolio and all its data."""
    portfolio_dir = get_portfolios_dir() / portfolio

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% 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.

Content

Scanner excerpt · mpt_portfolio/cli.py (reported line 1220)May include surrounding context.

python
f"Recommended cron schedule:\n"
        f"  [cyan]{cron}[/cyan]\n\n"
        f"{desc}\n"
        f"To install: run [bold]crontab -e[/bold] and add the line above.\n"
        f"Notifications will be sent via your configured method.",
        title="Scheduling Recommendation",
        border_style="blue",

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest describes a Modern Portfolio Theory optimizer for building, backtesting, and managing portfolios, but this file also defines SMTP settings and environment-variable resolution for email delivery. Notification support may be adjacent to management features, yet handling outbound email credentials is a materially broader behavior than portfolio optimization itself.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Resolving environment-backed SMTP usernames and passwords introduces credential-handling capability that is not directly required to optimize or backtest portfolios. The manifest does not mention messaging, email delivery, or secret-backed integrations that would justify this feature.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The save routine writes the full email configuration, including smtp_user and smtp_password, directly to a YAML file on disk. If the config originated from environment variables or user input, this can silently persist plaintext credentials where other local users, backups, logs, or accidental commits may expose them.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest describes a Modern Portfolio Theory optimizer for building, backtesting, and managing portfolios, which naturally covers analytics and reporting. However, this module explicitly implements outbound email delivery via SMTP, including optional attachments, which extends beyond local optimization/backtesting into external message transmission not indicated by the manifest description.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The function writes potentially sensitive portfolio details to a timestamped local file without any access control, minimization, consent prompt, or warning at the point of use. In shared environments, insecure file permissions or unexpected persistence can expose holdings, investment amounts, and strategy information to other local users or backup/sync systems.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The notify_email function opens an SMTP connection, optionally authenticates with credentials, and sends portfolio-related emails to configured recipients. For a skill described only as an optimizer that builds, backtests, and manages portfolios, external email delivery is an additional capability rather than an obvious implementation requirement.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code emails portfolio data and optional attachments over SMTP based on configuration, but it does not enforce transport security or provide any user-facing confirmation before transmitting sensitive financial information. If TLS is disabled, misconfigured, or intercepted, holdings and reports could be disclosed to unintended parties; attachments further increase the exposure.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
mpt_portfolio/config.py:80