Back to skill

Security audit

Swmm Gis

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed local GIS/SWMM preprocessing skill that runs QGIS/GRASS/Python workflows on user-provided project files and writes local outputs.

Install only if you are comfortable running local GIS preprocessing tools over your own DEM/vector data. Use a dedicated run/output directory because final-layer packaging overwrites files named subcatchments, flow, outfall, slope_percent.tif, overview.png, and manifest.json in that directory, and review the external Agentic SWMM project before relying on its MCP server/toolchain.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • 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
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The description emphasizes QGIS/GRASS-based preprocessing tasks such as delineating subcatchments, entropy-guided analysis, hotspot identification, and MCP tool exposure. This code does none of those things. Instead, it assumes subcatchment polygons already exist and performs area-weighted overlay analysis with landuse and soil polygons to derive SWMM runoff/infiltration parameters using lookup CSVs. While this is related to SWMM preprocessing, the primary purpose is materially different from the declared one. The use of GeoPandas rather than QGIS/GRASS is not by itself a mismatch, but the missing declared capabilities and the actual undeclared parameter-generation behavior make this a clear description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description centers on SWMM-oriented QGIS/GRASS preprocessing tasks, especially subcatchment delineation, polygon-to-CSV preprocessing, hotspot subcatchment identification, and MCP tool exposure. The supplied code instead implements a local cell-based raster classification workflow using DEM, soil, and land use inputs to infer aggregation classes from entropy and fuzzy similarity. It outputs rasters and polygons derived from classified cells, but it does not delineate hydrologic subcatchments, process user-supplied subcatchment polygons into builder-ready CSV, or expose any MCP/QGIS/GRASS integration. While there is some thematic overlap with geospatial preprocessing and entropy analysis, the primary behavior is materially different from the declared purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The declared description frames the skill as a broader QGIS/GRASS-backed SWMM preprocessing toolkit focused on subcatchment delineation, polygon-to-CSV preprocessing, entropy hotspot identification, and MCP tool exposure. The supplied code instead implements a much narrower and different function: selecting a DEM boundary pour point candidate based on elevation or flow accumulation and writing point/preview outputs. While this is plausibly related to hydrologic preprocessing for SWMM, it is not one of the declared capabilities, and the prominently described QGIS/GRASS and entropy-related functionality is absent. Therefore the code’s actual behavior is materially different from the declared purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description is about GIS/DEM preprocessing operations for SWMM workflows, especially delineation, conversion/preprocessing, entropy analysis, and MCP tool exposure. The supplied code does none of those core tasks. It is a visualization utility: it loads existing raster/vector layers, harmonizes CRS, renders them with matplotlib, adds lon/lat tick labels and a legend, and writes a PNG. While plotting QGIS/GRASS-derived layers is related to the same domain, the script’s primary purpose is materially different from the declared preprocessing functionality, so this is a clear description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The code is narrowly focused on packaging final GIS artifacts. It copies shapefile/raster inputs, computes a simplistic flow network and outfall from existing rasters, optionally creates an overview image, and emits a manifest. This is related to GIS/SWMM preprocessing, but it does not implement the main declared functions: no QGIS/GRASS delineation, no entropy-guided processing, no hotspot detection, no CSV conversion, and no MCP tool exposure. Its primary purpose is materially different: final-layer packaging and summarization of existing outputs.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

There is substantial overlap with the declared purpose around QGIS-backed preprocessing and exporting SWMM-ready intermediates from user-provided GIS layers. In particular, the code supports validating layer inputs, checking CRS consistency, normalizing GIS layers by reprojection/clipping, extracting overlay-derived landuse/soil attributes, and producing downstream SWMM parameter/intermediate artifacts. However, the description prominently claims additional capabilities that this code chunk does not perform: no watershed/subcatchment delineation logic appears here, no entropy-based analysis or hotspot detection exists, and there is no MCP server/tool exposure implementation. The code instead assumes subcatchment polygons and a network JSON are already prepared, then validates/transforms them. Because major declared capabilities are absent from the supplied code’s behavior, the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/qgis_prepare_swmm_inputs.py (reported line 61)May include surrounding context.

python
def qgis_env(*, proj_lib: Path | None, gisbase: Path | None) -> dict[str, str]:
    env = os.environ.copy()
    if proj_lib:
        env["PROJ_LIB"] = str(proj_lib)
    if gisbase:

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/qgis_raw_to_entropy_partition.py (reported line 75)May include surrounding context.

python
def qgis_env(*, proj_lib: Path | None, gisbase: Path | None) -> dict[str, str]:
    env = os.environ.copy()
    if proj_lib:
        env["PROJ_LIB"] = str(proj_lib)
    if gisbase:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill advertises and documents shell, file read/write, and environment-backed operations but does not declare an explicit tool permission scope. In an agent setting, missing scope boundaries can let the orchestrator grant broader-than-necessary capabilities, increasing the chance of unintended filesystem access, command execution, or data exposure when processing user-supplied paths and GIS assets.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script unconditionally deletes existing files in the user-specified output directory for the stems subcatchments, flow, and outfall, and also removes prior raster/overview/manifest outputs if present. Because final_dir is fully user-controlled and there is no confirmation, dry-run, or path safety guard, a mistaken or adversarial path can cause unintended data loss within that directory.

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/qgis_prepare_swmm_inputs.py (reported line 44)May include surrounding context.

python
def run_python(args: list[str]) -> dict[str, Any]:
    proc = subprocess.run(
        [sys.executable, *args],
        cwd=REPO_ROOT,
        check=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/qgis_prepare_swmm_inputs.py (reported line 80)May include surrounding context.

python
) -> str:
    cmd = [str(qgis_process), "run", algorithm, "--"]
    cmd.extend(f"{key}={value}" for key, value in params if value is not None)
    proc = subprocess.run(cmd, cwd=cwd, env=env, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    audit.append(
        {
            "algorithm": algorithm,

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/qgis_prepare_swmm_inputs.py (reported line 130)May include surrounding context.

python
suffix = path.suffix.lower()
    if suffix in {".tif", ".tiff"}:
        try:
            result = subprocess.run(
                ["gdalinfo", "-json", str(path)],
                capture_output=True, text=True, timeout=30,
            )

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/qgis_raw_to_entropy_partition.py (reported line 59)May include surrounding context.

python
def run_command(cmd: list[str], *, env: dict[str, str] | None, cwd: Path, audit: list[dict[str, Any]]) -> str:
    started = datetime.now(timezone.utc).isoformat()
    proc = subprocess.run(cmd, cwd=str(cwd), env=env, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    record = {
        "cmd": cmd,
        "started_at_utc": started,

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/qgis_raw_to_entropy_partition.py (reported line 97)May include surrounding context.

python
candidate = Path(gisbase) / "bin" / "grass"
    if not candidate.exists():
        return "unavailable"
    proc = subprocess.run([str(candidate), "--version"], text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    return (proc.stdout or proc.stderr).strip().splitlines()[0] if proc.returncode == 0 else "unavailable"

Static analysis

No suspicious patterns detected.