Back to skill

Security audit

trading212 Skill

Security checks for vulnerabilities and agentic risk

Overview

This Trading212 skill is mostly coherent with its stated purpose, but it can submit real-money trades and uses broad external configuration/storage paths without strong runtime safeguards.

Install only if you are comfortable giving this skill access to your Trading212 account data and potential trading authority. Keep TRADING212_DEMO=true unless you intend real-money trading, use restricted/read-only credentials where possible, avoid storing secrets in shared parent .env files, and review or relocate the snapshot and rules paths before use.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/trading212_skill.py:30
Finding

Shared Parent Environment File Can Redirect Operations to Live Trading

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/proposal_rules.py:24
Finding

Proposal Rules Are Loaded from an Unsafe External Default Path

Content
View full analysis
Dict[str, Any]: path = Path(os.environ.get("TRADING212_RULES_PATH", str(_CONFIG_PATH))) if not path.exists(): return {} with open(path, "r", encoding="utf-8") as fh: data = yaml.safe_load(fh) or {} return data.get("proposal_rules", {}) ``` ### Technical Analysis In the audited layout, `parents[3] / "config" / "rules.yaml"` resolves to `/tmp/config/rules.yaml`, rather than the documented project-local `config/rules.yaml`. As a result, a file in a shared directory can control proposal thresholds, DCA ticker lists, risk mode, stop-loss behavior, cost-averaging settings, and suggested trade quantities. YAML is parsed with `safe_load`, so this is not arbitrary Python code execution; the risk is unauthorized manipulation of financial decision inputs. The implementation also does not validate the loaded configuration against a schema or enforce safe numeric ranges. ### Attack Path 1. An attacker creates `/tmp/config/rules.yaml`. 2. The attacker supplies manipulated proposal settings, such as: ```yaml proposal_rules: risk_mode: high stop_loss_pct: 0 dca_min_cash: 0 dca_amount: 100000 dca_tickers: - "ATTACKER_SELECTED_TICKER" ``` 3. The user or agent invokes proposal mode. 4. The Skill loads the shared file instead of the packaged `config/rules.yaml`. 5. The generated recommendations reflect attacker-selected thresholds and symbols. 6. If the user accepts the recommendations, or another component invokes execution based on them, harmful trades may follow. ### Impact Assessment An attacker can man ...[truncated 241 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/snapshot.py:18
Finding

Sensitive Portfolio Snapshots Use a Shared Temporary Directory Without File Hardening

Content
View full analysis
/snapshots/ _DEFAULT_DIR = Path(__file__).resolve().parents[3] / "snapshots" ``` ```python def _snapshot_dir() -> Path: """Return the snapshot directory, creating it if needed.""" d = Path(os.environ.get("TRADING212_SNAPSHOT_DIR", str(_DEFAULT_DIR))) d.mkdir(parents=True, exist_ok=True) return d def _path_for_date(date_str: str) -> Path: return _snapshot_dir() / f"{date_str}.json" ``` ```python fp = _path_for_date(date_str) with open(fp, "w", encoding="utf-8") as fh: json.dump(snapshot, fh, indent=2, ensure_ascii=False) return fp ``` The stored object includes sensitive financial information: ```python snapshot: Dict[str, Any] = { "date": date_str, "total_value": round(total_value, 2), "cash": round(cash, 2), "positions": [ { "ticker": p["ticker"], "value": round(p["value"], 2), "quantity": p["quantity"], "avg_price": round(p.get("avg_price", 0), 4) if p.get("avg_price") else None, "current_price": round(p.get("current_price", 0), 4) if p.get("current_price") else None, } for p in positions ], } ``` ### Technical Analysis The default snapshot directory resolves to `/tmp/snapshots`, not a private project or user-data directory. Snapshot names are predictable dates, and files are opened through a normal path without: - Explicit `0600` permissions. - Directory ownership verification. - Symlink rejection. - Exclusive creation or safe replacement. - Atomic writes. The files disclose total portfolio value, cash, tickers, quantities, average acquisition prices, and current values. Existing snapshots are also trusted as inputs for performance and proposal calculations. ...[truncated 1078 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/trading212_skill.py:350
Finding

Real-Money Orders Can Be Submitted Without a Code-Enforced Confirmation Boundary

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Dependency Installation Is Not Reproducible or Integrity-Pinned

Content
View full analysis
=2.31.0 python-dotenv>=1.0.0 pyyaml>=6.0.1 ``` The documented installation command is: ```bash pip install -r {baseDir}/requirements.txt ``` ### Technical Analysis The package names are established dependencies, and the audit found no evidence of typosquatting, dependency confusion, or a malicious package. However, open-ended `>=` constraints allow future releases to be selected automatically, and no package hashes are supplied. This makes installation non-reproducible and leaves package authenticity dependent on the configured package index and TLS trust. A future compromised release, malicious mirror, or incompatible version could introduce code that executes during installation or runtime. ### Attack Path 1. An operator follows the documented `pip install` command. 2. The resolver selects any available package version satisfying the lower bound. 3. A compromised package index, mirror, account, or future matching release supplies altered content. 4. The package is installed into the Skill environment. 5. Installation hooks or imported package code execute with the privileges of the installer or Skill process. No evidence indicates that this attack is presently occurring; this is a supply-chain hardening weakness. ### Impact Assessment A compromised dependency could access the Skill process environment, including Trading212 credentials, portfolio data, and network access. If installation is performed with elevated privileges, the impact could extend to that installation context. Actual scope depends on the package source and installer privileges. ]]>
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
Findings (25)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill claims broad portfolio-analysis and safety-aware trading behavior that the underlying implementation reportedly does not actually provide, while still exposing API/client and order-placement functionality. In a financial context, this mismatch can mislead users and supervising systems into trusting nonexistent analysis, validation, or guardrails before trades are proposed or executed.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The client exposes direct order-placement primitives for market and limit orders, and the skill description explicitly says it can make trade proposals and place orders. In an agent setting, the absence of an explicit confirmation/approval gate in the action path creates a real risk of unintended or prompt-induced live trades, especially when demo can be switched to live via environment configuration.

Content

No source excerpt is available for this finding.

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 · scripts/trading212_skill.py (reported line 30)May include surrounding context.

python
from datetime import datetime, timedelta, timezone
from pathlib import Path

# Load .env from project root before any Trading212 imports.
_env_path = Path(__file__).resolve().parents[3] / ".env"
if _env_path.exists():
    from dotenv import load_dotenv

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

python
from pathlib import Path

# Load .env from project root before any Trading212 imports.
_env_path = Path(__file__).resolve().parents[3] / ".env"
if _env_path.exists():
    from dotenv import load_dotenv
    load_dotenv(_env_path)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill can place live market or limit orders directly from parsed parameters without any built-in confirmation gate, dry-run default, or explicit safety interlock for live accounts. In an agent setting, mis-parsed prompts, prompt injection from upstream context, or accidental invocation could trigger irreversible financial transactions and losses.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises and instructs use of capabilities that imply access to environment secrets, local files, and outbound network requests, but it does not declare any explicit tool scope or permission boundary. For a trading skill that can place orders and uses API credentials, this increases the chance of over-broad execution, secret exposure, or unintended network/file actions without transparent restriction.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The top-level description uses broad invocation language like portfolio overview, daily performance, or trade actions, which can match common finance-related requests too easily. This can cause the skill to activate in contexts where the user did not specifically intend Trading212 access, increasing the risk of unnecessary account-data exposure or escalation toward trade workflows.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The file instructs the agent to present output as a readable English summary, which imposes a language choice without user opt-in. The same policy appears again in the output format section, and no alternative language handling or justification is provided.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Example trigger phrases such as 'What should I do?' or 'Any trade suggestions?' are highly ambiguous and could be triggered by everyday conversation about markets rather than an explicit request to use this brokerage skill. In a trade-capable skill, accidental activation is more dangerous because it may expose holdings or steer the interaction toward order execution.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The instruction to present a human-readable English summary is a natural-language policy issue because it hard-codes a specific language for all users. There is no opt-in, locale selection, or documented rationale for restricting responses to English.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This reference explicitly documents a mode that can place orders and also states that snapshots are automatically written to disk, but it does not prominently warn about the real-world side effects of those actions. In a trading skill, unclear safety boundaries can lead to unintended financial transactions or silent local data persistence, especially if the caller assumes the skill is read-only or demo-only.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This file generates concrete buy/sell/reduce proposals, including quantities and rationales, but does not attach any explicit warning that the output is informational and may lead to financially impactful actions if acted on or passed to downstream order-placement components. In the context of a Trading212 skill that can also place orders, this omission increases the risk that users or automation treat these proposals as safe, authoritative trading instructions without adequate confirmation or suitability checks.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

cancel_order performs a destructive account action immediately with no built-in confirmation or secondary authorization. In a trading agent context, accidental, coerced, or ambiguous cancellation requests could interfere with user strategy, remove protective orders, or cause financial loss through missed execution.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Multiple user-facing messages are emitted in Dutch, including trade descriptions, validation errors, watchlist alerts, and allocation guidance. This forces a specific language/locale without any opt-in or documented justification, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

Across multiple mode descriptions, the skill repeatedly uses broad trigger examples that are not specific to Trading212, which raises the likelihood of unintentional routing. While largely a prompt-quality issue, the context makes it security-relevant because the skill can access financial data and eventually place orders.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

Several user-facing message examples and descriptions are written in Dutch, such as trade event descriptions and validation errors, while the rest of the reference is in English. Because the file does not state that the skill is Dutch-only or provide language selection, it appears to impose a locale on output without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

Alert messages and rebalance reasons in this section are also presented in Dutch, reinforcing a fixed-language behavior in otherwise English documentation. The file does not indicate that users can choose their preferred language or that the locale restriction is intentional and justified.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency is specified with a lower bound only, which allows future installs to resolve to different versions over time and weakens reproducibility and supply-chain control. In a skill that can access portfolio data and place trades, unexpected dependency changes can increase operational and security risk if a newly resolved version is vulnerable or malicious.

Content

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

text
requests>=2.31.0
python-dotenv>=1.0.0
pyyaml>=6.0.1

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +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
85% confidence
Finding

The manifest does not pin requests, so the actual installed version cannot be compared reliably against known advisories. In a network-facing trading skill, an unknowingly vulnerable HTTP client could expose credentials, weaken TLS/request handling, or leak sensitive information depending on the resolved version.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

Using python-dotenv with only a minimum version permits non-deterministic installs and makes it difficult to verify which release is deployed. This is a supply-chain hygiene issue that becomes more important in a financial-trading skill because environment handling may include sensitive API credentials.

Content

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

text
requests>=2.31.0
python-dotenv>=1.0.0
pyyaml>=6.0.1

Unverifiable Dependency: python-dotenv has 2 known advisory(ies) (CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
83% confidence
Finding

Because python-dotenv is unpinned, it is not possible to verify whether deployments are using a version affected by known advisories. This matters in a skill likely to use environment variables for brokerage API keys, where a vulnerable release could mishandle or expose sensitive configuration.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

An unpinned PyYAML dependency means builds may silently consume different releases, reducing reproducibility and making it harder to guarantee that only vetted versions are used. Because PyYAML has a history of security issues, this raises the chance of accidentally deploying an affected version.

Content

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

text
requests>=2.31.0
python-dotenv>=1.0.0
pyyaml>=6.0.1

Unverifiable Dependency: pyyaml has 8 known advisory(ies) (CVE-2019-20477 (Deserialization of Untrusted Data in PyYAML); CVE-2020-1747 (Improper Input Validation in PyYAML); CVE-2020-14343 (Improper Input Validation in PyYAML) +5 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

The unpinned pyyaml dependency is especially concerning because PyYAML has multiple historical deserialization and input-validation advisories, and the manifest provides no assurance that a safe version will be installed. If this skill parses YAML from untrusted or semi-trusted sources, a vulnerable version could increase the risk of code execution or other unsafe parsing outcomes.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The _ERROR_MESSAGES mapping contains fixed Dutch strings for common failures, and additional error text elsewhere also uses Dutch. This creates a language/locale policy issue because the skill does not offer a language choice or document that it is intentionally Dutch-only.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The manifest describes portfolio analysis, trade proposals, watchlist, history, dividends, allocation, and order placement. This file additionally reaches outside the skill directory to load a global .env file from the project root, which is a broader credential/config access capability not mentioned in the skill’s stated purpose.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.