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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
text

The installation section repeats the same command:

```markdown
**Install command:**

```bash
pip install gitmap-core
text

### 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
View 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
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 · tools.py (reported line 70)May include surrounding context.

python
cmd_prefix = _find_gitmap()
    full_cmd = cmd_prefix + args

    env = os.environ.copy()
    if extra_env:
        env.update(extra_env)

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

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 · tools.py (reported line 75)May include surrounding context.

python
env.update(extra_env)

    try:
        result = subprocess.run(
            full_cmd,
            cwd=str(cwd) if cwd else None,
            capture_output=True,

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.