Back to skill

Security audit

QGIS Agent

Security checks for vulnerabilities and agentic risk

Overview

The skill is purpose-aligned, but it opens a powerful unauthenticated local QGIS control server that can read and write files and optionally run Python code with weak default containment.

Install only for trusted local workflows. Run the server under a low-privilege account, keep it bound to localhost, stop it when not needed, set QGIS_ALLOWED_PATHS to dedicated input/output folders, and do not enable PYQGIS_ENABLE_EXEC unless you are in an isolated environment where arbitrary Python execution is acceptable. Confirm output paths before write or render operations because the server can create or overwrite files.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/server.py:85
Finding

Filesystem access controls are disabled by default

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/server.py:145
Finding

The configured path whitelist can be bypassed using nested or relative paths

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/server.py:242
Finding

Unbounded HTTP request bodies can exhaust memory or block the service

Content
View full analysis
Remediation
View remediation
MAX_BODY_BYTES: self._send(err("Request body too large"), 413) return None ``` 2. Configure socket read and processing timeouts. 3. Use a server implementation with bounded concurrency and robust request limits rather than the development-oriented standard-library `HTTPServer`. 4. Return HTTP 400 for malformed JSON instead of silently treating it as an empty object. 5. Apply rate limits per caller and limit the number of concurrent expensive QGIS jobs. 6. Where appropriate, place the service behind a local authenticated reverse proxy that enforces body-size, connection, and timeout limits. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/server.py:395
Finding

Unbounded rendering dimensions permit memory and CPU exhaustion

Content
View full analysis
Remediation
View remediation
MAX_WIDTH or h > MAX_HEIGHT or w * h > MAX_PIXELS: return self._send(err("Requested render exceeds configured limits"), 413) ``` 2. Set lower limits appropriate for the available memory and expected use cases. 3. Validate `extent` length and require finite numeric coordinates. 4. Limit the number and complexity of layers rendered per request. 5. Add a render timeout and cancel jobs that exceed it. 6. Serialize or queue expensive processing with per-caller quotas rather than allowing unrestricted synchronous work. 7. Monitor render duration, dimensions, pixel count, and memory failures. 8. Combine these controls with API authentication and local rate limiting. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (19)

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The API advertises /pyqgis as executing arbitrary PyQGIS code, but the implementation uses unrestricted Python exec() with a globals dict that still allows access to Python builtins and imports. This mismatch understates the attack surface and can lead users to enable a full arbitrary-code-execution endpoint under the mistaken belief that it is limited to PyQGIS scripting.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The documentation claims path allowlisting applies to /call and /pyqgis, but /pyqgis executes arbitrary Python code, which can trivially bypass any string-based path check by constructing paths at runtime, importing os/pathlib, or performing non-file actions entirely outside the validator. This creates a dangerous false sense of protection for operators who may rely on the documented whitelist as a security boundary.

Content

No source excerpt is available for this finding.

exec() call detected

High
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

The /pyqgis endpoint executes user-supplied code with Python exec(), which permits arbitrary Python execution, not just limited PyQGIS operations. Any local process able to reach 127.0.0.1 can read/write files, run OS commands, access network resources through Python, and fully compromise the QGIS process and its data.

Content

Scanner excerpt · scripts/server.py (reported line 447)May include surrounding context.

python
t0 = time.time()
        try:
            with redirect_stdout(buf):
                exec(code, g)  # noqa: S102 - 显式开启的逃生舱口
        except Exception as e:
            return self._send(err(e, traceback=traceback.format_exc()[-1500:]))
        return self._send(ok({"stdout": buf.getvalue(),

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The entire skill description and user-facing instructions are written in Chinese, with no indication that users may choose another language or that the skill is intended only for a Chinese-language audience. Under the stated policy, forcing a specific language without opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

任意能发 HTTP 请求的智能体:无需任何客户端,直接 curl:

bash
curl -s http://127.0.0.1:8767/health
curl -s "http://127.0.0.1:8767/search?q=buffer"
curl -s -X POST http://127.0.0.1:8767/call -H "Content-Type: application/json" \
  -d '{"name":"native:buffer","arguments":{"INPUT":"C:/data/roads.shp","DISTANCE":500,"OUTPUT":"C:/out/roads_buf.gpkg"}}'

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README explicitly advertises a /pyqgis endpoint that can execute arbitrary PyQGIS code, and the safety warning is brief and easy to overlook relative to the powerful capability being exposed. In an agent-integrated context, even localhost-only execution can let a prompt-driven client run arbitrary local code, access files, or modify projects if the endpoint is enabled, so the documentation should make the risk much more prominent.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Probe whether the service is up:

bash
curl -s http://127.0.0.1:8767/health
# {"status":"ok","server":"qgis-agent-server","version":"1.0","algorithms":1000,"providers":6,...}

External Transmission

Medium
Category
Data Exfiltration
Confidence
87% confidence
Finding

Although the endpoint is localhost, the skill instructs the agent to send project metadata and filesystem paths over HTTP to a local service and to open/save project files on request. In this context, localhost acts as an inter-process trust boundary; a compromised or overly permissive local server could expose sensitive geospatial data, layer metadata, and enable unauthorized file access or modification.

Content

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

bash
# Inspect the current project and layers (field list, feature count, CRS)
curl -s http://127.0.0.1:8767/project

# Open / save a project
curl -s -X POST http://127.0.0.1:8767/project/open -H "Content-Type: application/json" -d '{"path":"C:/data/demo.qgz"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
87% confidence
Finding

This is the Chinese-language duplicate of the same localhost project-inspection and open/save workflow. The risk is not classic external transmission, but disclosure of project structure, CRS, field lists, and file paths to a separate local HTTP service plus potential unauthorized file operations if the service is misconfigured or abused.

Content

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

bash
# 查看当前工程与图层(含字段列表、要素数、CRS)
curl -s http://127.0.0.1:8767/project

# 打开 / 保存工程
curl -s -X POST http://127.0.0.1:8767/project/open -H "Content-Type: application/json" -d '{"path":"C:/data/demo.qgz"}'

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The entire API documentation is written in Chinese, with no indication that language selection is optional or that the skill is intentionally limited to a Chinese-speaking audience. This can constitute a language/locale policy violation when a specific language is imposed without user opt-in or documented justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation describes a /pyqgis endpoint that can be enabled to run PyQGIS code, but it does not explicitly warn that this is effectively arbitrary code execution inside the QGIS host process. Even though it is disabled by default and bound to 127.0.0.1, local exposure still creates substantial risk because any local user, malware, browser-assisted localhost attack, or chained agent/tool misuse could execute code once the flag is enabled.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

Natural-language policy issues apply to all file types, including markdown. This file forces a specific language for all headings, instructions, and examples, with no opt-in, alternate locale, or justification that the skill is region- or language-specific.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/examples.md (reported line 10)May include surrounding context.

缓冲区

bash
curl -s -X POST http://127.0.0.1:8767/call -H "Content-Type: application/json" -d '{
  "name": "native:buffer",
  "arguments": {"INPUT":"D:/data/roads.shp","DISTANCE":500,"SEGMENTS":5,
                "END_CAP_STYLE":0,"JOIN_STYLE":0,"OUTPUT":"D:/out/roads_buf_500m.gpkg"}

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring presents the service description, API overview, and safety notes entirely in Chinese, and the runtime startup messages are also emitted in Chinese. This imposes a specific language on users and operators without any documented opt-in, fallback, or locale selection, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/server.py (reported line 443)May include surrounding context.

python
g = {"QgsApplication": QgsApplication, "QgsProject": QgsProject,
             "QgsVectorLayer": QgsVectorLayer, "QgsRectangle": QgsRectangle,
             "QgsWkbTypes": QgsWkbTypes, "Processing": Processing, "registry": REGISTRY,
             "processing": __import__("processing")}
        t0 = time.time()
        try:
            with redirect_stdout(buf):

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The response returned by api_docs() contains user-facing endpoint descriptions entirely in Chinese. Because these strings are surfaced to clients programmatically and there is no mechanism to request another language or opt in to Chinese, the server enforces a locale choice.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The example instructs the agent to save results as a GeoPackage and render a preview image, which can modify or create user files. The nearby example text does not warn that the workflow may write output files or encourage confirmation before choosing output paths, which is relevant for markdown-based skill descriptions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The /call endpoint allows caller-controlled output paths, which means the service can write files to locations selected by the requester. Without a clear warning and path restrictions, users may underestimate the risk of overwriting files, planting data in sensitive directories, or abusing the service as a filesystem write primitive through agent-driven or local requests.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This markdown file contains many example commands that create output files such as .gpkg, .tif, and .png, which can overwrite existing files or alter user data locations. The document provides usage examples but does not include a user-facing warning about file creation/overwrite effects or the need to verify output paths before running them.

Content

No source excerpt is available for this finding.