Back to skill

Security audit

Git-Map

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-aligned, but its local server can run credential-bearing map changes without authentication or clear safeguards.

Review this before installing or running the server. Use least-privilege ArcGIS credentials or scoped tokens, avoid passing passwords as tool parameters, run it only in a trusted local environment, and avoid exposing the localhost service while sensitive repositories or production Portal content are reachable.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server.py:123
Finding
Unauthenticated State-Changing HTTP Tools with Permissive CORS## Vulnerability Details **File Location**: `server.py:123-127`, `server.py:143-148`, `server.py:177-201`, and `server.py:226` **Vulnerability Type**: Missing authentication and authorization; unrestricted cross-origin access **Risk Level**: High ### Vulnerable Code ```python self.send_header("Access-Control-Allow-Origin", "*") self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") self.send_header("Access-Control-Allow-Headers", "Content-Type") self.end_headers() self.wfile.write(body) ``` ```python def do_OPTIONS(self) -> None: """Handle CORS preflight.""" self.send_response(200) self.send_header("Access-Control-Allow-Origin", "*") self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") self.send_header("Access-Control-Allow-Headers", "Content-Type") self.end_headers() ``` ```python def do_POST(self) -> None: """Handle POST tool calls: POST /tools/{tool_name}""" path = urllib.parse.urlparse(self.path).path.rstrip("/") if not path.startswith("/tools/"): self.send_json({"error": "Not found"}, 404) return tool_name = path[len("/tools/"):] if tool_name not in TOOL_REGISTRY: self.send_json( { "error": f"Unknown tool: {tool_name}", "available": list(TOOL_REGISTRY.keys()), }, 404, ) return params = self.read_body() tool_fn = TOOL_REGISTRY[tool_name]["fn"] try: result = tool_fn(**params) ``` ```python server = HTTPServer(("localhost", PORT), GitMapHandler) ``` ### Technical Analysis The HTTP service executes tool functions directly from attacker-supplied JSON without authenticating the caller or authorizing the requested operation. The exposed registry includes state-changing operations such as committing changes, deleting branches, pulling data, and pushing change ...[truncated 2272 chars]
Remediation
## Remediation Suggestions - Require authentication for every tool endpoint, using a cryptographically strong bearer token or another local authentication mechanism. - Perform operation-level authorization and restrict destructive tools to explicitly authorized clients. - Replace wildcard CORS with an explicit allowlist of trusted origins. Reject requests with absent or untrusted `Origin` headers where browser access is supported. - Restrict `cwd` to canonical paths beneath explicitly configured repository roots: 1. Resolve the path with `Path.resolve()`. 2. Reject nonexistent paths and symbolic-link escapes. 3. Verify that the resolved path is beneath an approved root. 4. Confirm that the path is a valid GitMap repository. - Add request body size limits, strict JSON validation, and per-tool parameter schemas. - Consider exposing the service through a Unix-domain socket protected by filesystem permissions instead of a TCP port. - Run the server under a dedicated least-privileged account and avoid inheriting credentials that are unnecessary for a given operation. - Disable destructive tools by default and require explicit configuration before enabling push, pull, commit, or branch deletion.

T09 · Insecure Skill Coding Practices

Warning
Location
tools.py:107
Finding
Portal Passwords Exposed in Subprocess Command-Line Arguments## Vulnerability Details **File Location**: `tools.py:107-123`, `tools.py:322-323`, and `tools.py:349-350` **Vulnerability Type**: Plaintext credential exposure through process arguments **Risk Level**: Medium ### Vulnerable Code ```python def _portal_flags( portal_url: Optional[str], username: Optional[str], password: Optional[str], ) -> list[str]: """ Build Portal credential CLI flags. Args: portal_url: Portal or ArcGIS Online URL. username: Portal username. password: Portal password. Returns: list[str]: CLI flags to append (may be empty). """ flags: list[str] = [] if portal_url: flags += ["--url", portal_url] if username: flags += ["--username", username] if password: flags += ["--password", password] return flags ``` ```python args += _portal_flags(portal_url, username, password) return _run(args, cwd=cwd, timeout=120) ``` The same construction is used by both `gitmap_push` and `gitmap_pull`. ### Technical Analysis `_portal_flags` appends the plaintext Portal password to the child process argument vector as the value of `--password`. `_run` subsequently passes this argument list to `subprocess.run`. Avoiding `shell=True` prevents shell metacharacter injection, but it does not protect secrets placed in process arguments. Depending on the operating system and process-isolation policy, command-line arguments may be observable through process inspection utilities, monitoring agents, audit logs, crash diagnostics, or process metadata. The password remains exposed for the lifetime of the GitMap subprocess. ### Attack Path 1. A user invokes `gitmap_push` or `gitmap_pull` and supplies a Portal password. 2. `_portal_flags` creates the argument pair `["--password", password]`. 3. `_run` starts the GitMap process with that plaintext password in its argument vect ...[truncated 949 chars]
Remediation
## Remediation Suggestions - Do not place passwords, tokens, or other secrets in subprocess argument vectors. - Prefer the GitMap Python API so credentials can be passed directly in memory without creating a credential-bearing subprocess command line. - If the CLI must be used, use a supported protected mechanism such as: - Standard input. - A dedicated environment variable. - A credential helper or operating-system secret store. - A temporary credential file created with restrictive permissions and securely removed immediately after use. - Prefer short-lived, narrowly scoped API tokens over reusable account passwords. - Ensure error messages, process logs, audit events, and telemetry redact credential values. - Run subprocesses under a dedicated account and configure the operating system to restrict access to process metadata. - Document credential rotation procedures in case process arguments have already been captured.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:15
Finding
Unpinned Third-Party Package Installation## Vulnerability Details **File Location**: `SKILL.md:15-18` and `SKILL.md:222-226` **Vulnerability Type**: Uncontrolled dependency version and integrity **Risk Level**: Medium ### Vulnerable Code ```markdown ### Install GitMap Core ```bash pip install gitmap-core ``` ``` The installation section repeats the same command: ```markdown **Install command:** ```bash pip install gitmap-core ``` ``` ### Technical Analysis The documented installation command retrieves the latest package version selected by the configured Python package index. It does not pin a reviewed version, constrain transitive dependencies, or verify package hashes. Python package installation can execute packaging-related code, and the installed dependency is later imported by both `server.py` and `tools.py`. Therefore, a compromised or unexpectedly changed release can affect installation-time behavior and all subsequent skill operations. The audited project does not vendor or independently verify the effective `gitmap-core` implementation. This finding represents a supply-chain exposure rather than evidence that the current `gitmap-core` package is malicious. ### Attack Path 1. A user follows the documented command `pip install gitmap-core`. 2. Pip resolves the currently available package and its transitive dependencies from the configured index. 3. If an upstream release, maintainer account, package index, or transitive dependency has been compromised, pip downloads the altered code without project-specific hash verification. 4. The compromised package can execute during installation or when imported. 5. `server.py` imports `gitmap_core` at startup, while `tools.py` imports its connection, map, and repository components during tool execution. 6. Malicious dependency code consequently runs with the privileges and credentials of the skill process. ### Impact Assessment A compromised dependency can obtain the full authority ...[truncated 487 chars]
Remediation
## Remediation Suggestions - Pin `gitmap-core` to a specifically reviewed version rather than installing the latest release. - Maintain a lock file that fixes all transitive dependency versions. - Generate and verify package hashes, using pip's `--require-hashes` mode where practical. - Install only from an explicitly configured, trusted package index or an internally controlled artifact repository. - Review dependency provenance, release signatures, maintainership changes, and published security advisories. - Use automated dependency scanning and controlled update procedures rather than unconstrained installation. - Test upgrades in an isolated environment before updating the production skill. - Run installation and execution with least privilege and avoid exposing long-lived Portal credentials during dependency installation.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (10)

Env Variable Harvesting

High
Category
Data Exfiltration
Content
cmd_prefix = _find_gitmap()
    full_cmd = cmd_prefix + args

    env = os.environ.copy()
    if extra_env:
        env.update(extra_env)
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.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill exposes push and pull operations against a live ArcGIS Portal but does not prominently warn that these actions can overwrite remote map state or import unexpected remote changes. In an agent context, that omission increases the chance of unsafe or unintended destructive actions, especially when credentials can be supplied via environment variables or per-call parameters.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The server exposes HTTP endpoints for operations that accept sensitive credentials such as portal usernames and passwords, but it provides no authentication, authorization, or user-facing disclosure about the sensitivity of those actions. Although it binds to localhost, any local process or a browser context interacting with a local service can invoke these endpoints, and the permissive CORS policy increases the chance of unintended cross-origin access patterns.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
env.update(extra_env)

    try:
        result = subprocess.run(
            full_cmd,
            cwd=str(cwd) if cwd else None,
            capture_output=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The helper explicitly builds --username and --password CLI arguments, which can expose credentials to local process inspection, shell history wrappers, audit logs, crash reports, and telemetry. In an agent/tooling context, this is more dangerous because secrets may be propagated through orchestration logs or visible to other co-tenant processes on the host.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
`gitmap_push` sends repository changes to ArcGIS Portal and may include portal credentials, but the function contains no confirmation prompt, print/log disclosure, or warning comment beyond a terse purpose statement. This is a safety-relevant network action that can affect remote data and should be clearly disclosed to the user.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
`gitmap_pull` retrieves the latest map state from ArcGIS Portal, a network operation that can change the local working state, but there is no confirmation, visible disclosure, or warning about this effect. The docstring states what it does but does not warn about local state changes or remote data access.

Intent-Code Divergence

Low
Confidence
96% confidence
Finding
The overview states the skill "wraps the `gitmap` CLI as thin subprocess calls," and later notes output is "raw CLI text," which implies command-line invocation behavior. However, the installation section later claims "The skill uses the `gitmap_core` Python package directly for API access," which is a materially different implementation model and creates an intent/documentation contradiction.

Missing User Warnings

Low
Confidence
87% confidence
Finding
The API exposes state-changing repository actions such as commit, branch creation/deletion, push, and pull over unauthenticated local HTTP without explicit confirmation or warning. In this skill context, these are intended features, but exposing destructive operations through a simple POST interface means other local software could trigger repository changes unexpectedly.

Intent-Code Divergence

Low
Confidence
96% confidence
Finding
The module documentation says each function is a thin wrapper around the `gitmap` CLI, but `gitmap_list` and `gitmap_log` import and use `gitmap_core` Python APIs directly instead of invoking the CLI. This is an active contradiction in the code documentation about how the skill operates, even though the overall purpose remains related to GitMap.

Static analysis

No suspicious patterns detected.