Back to skill

Security audit

Swmm Uncertainty

Security checks for vulnerabilities and agentic risk

Overview

This looks like a legitimate SWMM uncertainty-analysis skill, but it needs review because one output-writing path can escape its intended directory and the skill runs batch local simulations.

Install only in a workspace where you trust the Agentic SWMM toolchain and sibling skills. Use fresh run/output directories, keep sample counts modest, prefer --dry-run first, and do not pass untrusted node names or paths until the node-name output-path issue is fixed.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/monte_carlo_propagate.py:104
Finding

Path Traversal Through Node-Derived Output Filenames

Content
View full analysis
None: path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(obj, indent=2, sort_keys=True), encoding="utf-8") ``` ### Technical Analysis Each user-supplied node identifier is interpolated directly into two output filenames: - `ensembles/_ensemble.json` - `entropy/_entropy.json` There is no validation that the identifier is a simple SWMM node name and no check that the resolved destination remains under `ensemble_dir` or `entropy_dir`. Python's `pathlib` preserves and resolves path separators and `..` components during filesystem access. Consequently, a value containing traversal sequences can cause the generated JSON files to be written outside their intended directories. For example, a node identifier shaped like `../../target` produces paths equivalent to: ```text /ensembles/../../target_ensemble.json /entropy/../../target_entropy.json ``` Exploitation requires `build_ensemble_payload()` to successfully extract data for the supplied identifier befor ...[truncated 1999 chars]
Remediation
View remediation
str: if not node or not SAFE_NODE_RE.fullmatch(node): raise ValueError(f"Unsafe SWMM node identifier: {node!r}") if node in {".", ".."}: raise ValueError(f"Unsafe SWMM node identifier: {node!r}") return node ``` Explicitly reject `/`, `\`, absolute paths, null characters, and traversal components. 2. **Enforce destination-path confinement** Validate the resolved destination immediately before every write: ```python def confined_output_path(base: Path, filename: str) -> Path: base_resolved = base.resolve() destination = (base_resolved / filename).resolve() try: destination.relative_to(base_resolved) except ValueError as exc: raise ValueError("Output path escapes its designated directory") from exc return destination ``` Then construct output paths as follows: ```python safe_node = validate_node_name(node) ensemble_path = confined_output_path( ensemble_dir, f"{safe_node}_ensemble.json", ) entropy_path = confined_output_path( entropy_dir, f"{safe_node}_entropy.json", ) ``` 3. **Separate display identifiers from filesystem names** Prefer generating filenames from an internal index or a safe digest rather than directly from external identifiers: ```python filename_id = hashlib.sha256(node.encode("utf-8")).hexdigest()[:16] ``` Preserve the original node identifier only inside the JSON payload. 4. **Avoid unintended overwrites** If replacing existing output is not required, use exclusive creation or check for an existing destination before writing. Atomic writes through a ...[truncated 426 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a broad uncertainty-analysis skill focused on propagating uncertainty through SWMM, computing output envelopes/entropy, running sensitivity methods (OAT/Morris/Sobol), generating rainfall ensembles, and building uncertainty-source decomposition artifacts. The supplied code does not implement those behaviors. Instead, it performs a narrower preprocessing task: inspecting an INP file to recommend which parameters should be perturbed in a Monte Carlo prior definition. While this is tangentially related to uncertainty workflows, it is not one of the declared primary capabilities, and none of the advertised analysis or report-generation functions appear in this code chunk. Therefore the code's actual purpose is materially different from the declared description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description covers a much broader uncertainty-analysis skill suite than this code chunk actually provides. This script is narrowly focused on sensitivity analysis, specifically OAT, Morris, and Sobol methods, which does match one part of the description. However, the declared purpose also claims uncertainty propagation, rainfall ensemble generation, hydrograph envelope/output entropy computation, and integrated uncertainty-source decomposition artifacts; none of those behaviors appear in the code. Additionally, every trial is scored against an observed time series using RMSE/peak/mean error, introducing a calibration-like dependence on observations that is not aligned with the declared emphasis on uncertainty propagation without treating runs as calibration. So the description overstates the implemented functionality in a material way.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description focuses on uncertainty propagation, sensitivity analysis, rainfall ensemble generation, and decomposition of uncertainty sources. The provided code does not implement or test any of those capabilities. Instead, it tests a separate behavior: inspecting a SWMM input file and recommending relevant parameters (e.g., Horton infiltration parameters and routing-related parameters) with rationale metadata. That is a materially different primary purpose from the declared uncertainty-analysis workflow, so this is a mismatch.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `scripts/fuzzy_membership.py`

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill documentation describes capabilities that include shell execution and broad filesystem access, but it does not declare any explicit tool scope or allowed-tools boundary. In an agent setting, this can cause over-privileged execution because the runtime may permit more tools than the skill actually needs, increasing the chance of unintended command execution, file modification, or environment disclosure.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/rainfall_ensemble.py (reported line 816)May include surrounding context.

python
"files": {"inp": str(inp_path)},
        }

    proc = subprocess.run(
        ["swmm5", str(inp_path), str(rpt_path), str(out_path)],
        capture_output=True,
        text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/sensitivity.py (reported line 82)May include surrounding context.

python
run_dir.mkdir(parents=True, exist_ok=True)
    rpt = run_dir / "model.rpt"
    out = run_dir / "model.out"
    proc = subprocess.run(
        ["swmm5", str(inp), str(rpt), str(out)],
        capture_output=True,
        text=True,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The script prepends another skill directory to sys.path and then imports Python modules from it at runtime, creating a cross-skill trust boundary violation. If the swmm-calibration skill or repository contents are modified, this script will execute attacker-controlled code during import, which is especially risky in an agent ecosystem where skills should be isolated and independently trusted.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/uncertainty_propagate.py (reported line 70)May include surrounding context.

python
"--node",
        node,
    ]
    proc = subprocess.run(cmd, cwd=REPO_ROOT, capture_output=True, text=True)
    parsed: dict[str, Any] = {}
    if proc.stdout.strip():
        try:

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The documentation repeatedly states that the skill writes multiple artifacts, generated inputs, summaries, and trial files into run directories without a prominent warning about filesystem side effects. In an agentic environment this can lead to unintended overwrites, storage exhaustion, or writing into sensitive locations if user-supplied paths are not constrained.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill instructs users to remove --dry-run to execute SWMM for every generated trial, which can trigger large batch runs with substantial CPU, disk, and process impact. In an agent workflow this is risky because small input changes can fan out into many solver invocations, creating denial-of-wallet/denial-of-service style resource consumption or unintended execution at scale.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This code performs a filesystem write by creating parent directories and writing JSON output, but it provides no confirmation prompt, user-facing log/print, or comment/docstring disclosing that behavior. For code files, file writes should be flagged when they lack any form of user disclosure unless the warning is provided elsewhere.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code performs a filesystem write to a user-specified path via write_json, which creates parent directories and writes JSON output. There is no confirmation prompt, print/log message, or inline warning disclosing that the script will create or overwrite files at the provided path.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The function creates a run directory, writes a patched model.inp, and invokes the external swmm5 binary, which also produces report/output artifacts. While the module docstring describes outputs at a high level, there is no explicit user-facing warning, confirmation, or inline disclosure near the write-and-execute path about these filesystem changes and subprocess behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.