Back to skill

Security audit

Progressive Validator

Security checks for vulnerabilities and agentic risk

Overview

The skill is not malicious, but its validation records and generated shell commands can mislead users or automation into trusting unverified backtest results or unsafe command text.

Install only if you treat this as a lightweight local tracker, not an authoritative validation gate. Manually verify every backtest window and metric, do not rely on stored passed statuses for promotion, and do not copy or auto-run suggested commands when strategy names or paths may contain shell metacharacters.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
validator.py:127
Finding

Validation Gates Can Be Bypassed with Unverified Results

Content
View full analysis
Optional[str]: """Determine the next stage a strategy should run.""" history = self.results.get(strategy_name, {}) for stage in self.get_stage_order(): if stage not in history or history[stage].get("status") != "passed": return stage return None # All stages passed ``` ```python def record_result( self, strategy_name: str, stage_name: str, status: str, sharpe: Optional[float] = None, drawdown: Optional[float] = None, profit: Optional[float] = None, reason: Optional[str] = None, ): """Record the outcome of a validation stage.""" if strategy_name not in self.results: self.results[strategy_name] = {} self.results[strategy_name][stage_name] = { "status": status, "sharpe": sharpe, "drawdown": drawdown, "profit": profit, "reason": reason, "timestamp": datetime.now().isoformat(), } self._save_results() print(f"Recorded: {strategy_name} / {stage_name} -> {status}") ``` ```python elif args.command == "record": validator.record_result( strategy_name=args.strategy_name, stage_name=args.stage, status=args.status, sharpe=args.sharpe, drawdown=args.drawdown, profit=args.profit, reason=args.reason, ) ``` ### Technical Analysis The application treats the caller-supplied `status` value as the authoritative validation outcome. It records a stage as passed without checking: - Whether `stage_name` is a configured stage. - Whether preceding stages have passed. - Whether drawdown is below the stage-specific `max_dd`. - Whether final-stage Sharpe, drawdown, and profit sa ...[truncated 2041 chars]
Remediation
View remediation
= min_sharpe` - `drawdown <= max_drawdown` - `profit >= min_profit` 5. Reject missing, non-finite, negative, or otherwise invalid metric values where they are not meaningful. 6. Store a cryptographic hash of the strategy file with each result and invalidate prior results when the file changes. 7. Enforce the documented result-expiration policy by parsing timestamps and rejecting results older than 30 days. 8. If manual overrides are necessary, implement them as an explicit, auditable operation with a justification rather than overloading the normal passing state. 9. Add tests covering excessive drawdown, missing metrics, unknown stages, out-of-order stages, changed strategy files, stale results, and final-stage acceptance failures. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
validator.py:227
Finding

Shell Command Suggestion Contains Unquoted User-Controlled Arguments

Content
View full analysis
Optional[str]: """Generate the backtest submission command for the next validation stage. Submission is handled by the backtest-poller skill. ``cli_path`` should point to that skill's cli.py (default assumes skills are sibling directories). """ next_stage = self.get_next_stage(strategy_name) if not next_stage: return None stage = self.stages[next_stage] return ( f"python3 {cli_path} submit " f"--main-file {strategy_file} " f"--name {strategy_name}_{next_stage}" ) ``` The generated value is presented to the caller as a command: ```python print(f"\nSuggested command:\n {cmd}\n") ``` ### Technical Analysis `strategy_name` and `strategy_file` originate from positional CLI arguments and are interpolated directly into shell command text. `cli_path` is also inserted without shell-safe quoting, although the current CLI uses its default value. No quoting or escaping is applied with a mechanism such as `shlex.quote()`. Consequently, spaces, command separators, command substitutions, redirections, or other shell metacharacters in these values retain their shell meaning if the displayed command is copied into a shell or automatically executed by an agent. The current code prints the command and does not itself pass it to `subprocess` or a shell. Therefore, exploitation requires a user or downstream automation system to execute the generated suggestion. This limitation reduces immediacy but does not remove the risk because the explicit purpose of the output is to recommend a command for execution. ### Attack Path 1 ...[truncated 1413 chars]
Remediation
View remediation
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill includes operational commands that can write local state via validator.py record ... and likely maintains tracking data, but it declares no explicit tool scope such as permissions or allowed-tools. That mismatch weakens least-privilege controls because an agent may be permitted to perform file-writing behavior without the skill clearly constraining or documenting those capabilities.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file presents skip rules as authoritative validation policy, but the implementation never enforces them when suggesting stages or recording results. A user or downstream agent can mark later stages as passed, skip required stages, or rely on stale results, causing invalid backtest promotion and undermining the trustworthiness of the validation pipeline.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The generated command claims to submit the next validation stage, but it does not include the stage-specific date window or acceptance thresholds from configuration. In this skill context, that can cause operators or agents to run a generic backtest under the wrong scope while believing stage constraints were applied, producing misleading validation results and weakening the fail-fast safety model.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.