T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- scripts/server.py:85
- Finding
- Filesystem access controls are disabled by default<![CDATA[ ## Vulnerability Details **File Location**: `scripts/server.py:85-90`, `scripts/server.py:145-148` **Vulnerability Type**: Missing secure-by-default filesystem access control **Risk Level**: High ### Vulnerable Code ```python # Path whitelist (empty = unrestricted) ALLOWED_PATHS = [ os.path.normpath(p.strip().rstrip("/\\")) for p in os.environ.get("QGIS_ALLOWED_PATHS", "").split(";") if p.strip() ] PYQGIS_EXEC_ENABLED = os.environ.get("PYQGIS_ENABLE_EXEC", "0") == "1" ``` ```python def check_paths(args): """Validate that file paths in arguments are inside the whitelist.""" if not ALLOWED_PATHS: return None ``` The same unsafe default is explicitly documented in `SKILL.md:119-121` and `SKILL.md:239-241`. ### Technical Analysis The `QGIS_ALLOWED_PATHS` environment variable is optional. When it is absent or empty, `check_paths()` immediately permits every path. The unauthenticated HTTP API can subsequently pass attacker-controlled paths to QGIS Processing algorithms and to project and rendering operations. Relevant operations include: - `/call`, which passes input and output paths to any registered QGIS Processing algorithm. - `/project/open`, which reads a caller-selected QGIS project. - `/project/save`, which writes a project to a caller-selected path. - `/render`, which writes a PNG to a caller-selected path. Binding the service to `127.0.0.1` reduces network exposure but is not an authorization mechanism. Any local process that can connect to the port can submit requests, including compromised applications, malware operating with the same user privileges, or potentially browser-mediated localhost requests where request construction is possible. The accessible scope is determined by the operating-system privileges of the QGIS server process rather than by the task's legitimate data directory. ### Attack Path 1. The user starts the server without setting `QGIS_ALLOWED_PATHS`, as permitted by the default configura ...[truncated 1476 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Fail closed at startup when no whitelist is configured: ```python raw_allowed_paths = os.environ.get("QGIS_ALLOWED_PATHS", "") if not raw_allowed_paths.strip(): raise RuntimeError("QGIS_ALLOWED_PATHS must be configured") ``` 2. Separate readable input directories from writable output directories. 3. Run the service under a dedicated, low-privilege operating-system account that cannot access unrelated user files. 4. Add authentication, such as a randomly generated bearer token, to every non-health endpoint. 5. Restrict processing providers or algorithms to an explicit allowlist where possible. 6. Prevent accidental replacement of existing files unless the caller explicitly requests overwrite and is authorized. 7. Consider requiring user confirmation outside the server for destructive operations, but do not rely on agent instructions as the primary enforcement mechanism. 8. Log authenticated caller identity, algorithm ID, input paths, output paths, and operation results for security review. ]]>
