Back to skill

Security audit

GIMHub

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly a real GIMHub publishing helper, but it can upload broad local file contents and persist or redirect credentials in ways users should review first.

Install only if you are comfortable with an agent publishing code and issue content to GIMHub. Use explicit --files selections, run it from a clean project directory, avoid storing sensitive files nearby, do not set GIMHUB_URL unless you trust that exact server, and protect or rotate the token saved under ~/.gimhub/config.json.

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 (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/gimhub.py:130
Finding
Overbroad Recursive File Collection Can Expose Sensitive Local Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gimhub.py:130-148` **Vulnerability Type**: Excessive local file access and unintended data upload **Risk Level**: High ### Vulnerable Code ```python # Collect files files = [] if args.files: for file_path in args.files: path = Path(file_path) if path.exists(): files.append({ "path": str(path), "content": path.read_text(), "mode": "update", }) else: # Push all files in current directory (excluding hidden, common ignores) ignore = {".git", "__pycache__", "node_modules", ".venv", "venv"} for path in Path(".").rglob("*"): if path.is_file() and not any(p in path.parts for p in ignore): if not path.name.startswith("."): try: content = path.read_text() files.append({ "path": str(path), "content": content, "mode": "update", }) except UnicodeDecodeError: pass # Skip binary files ``` The collected contents are subsequently transmitted: ```python result = api_request("POST", f"/api/repos/{repo_path}/git/push", { "branch": args.branch, "files": files, "message": args.message, }, token=token) ``` ### Technical Analysis When `push` is invoked without `--files`, the program recursively reads every non-binary, non-hidden file beneath the current working directory. Its denylist only excludes five directory names and does not account for many sensitive file types, including: - Plaintext configuration and credential files - Logs and database exports - Conversation or session records - Deployment and infrastructure configuration - Proprietary source code unrelated to the inten ...[truncated 1872 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove recursive upload as the default behavior. Require explicit file paths, a manifest, or an explicit opt-in such as `--all`. 2. Restrict file resolution to a validated repository root and reject paths that resolve outside it. 3. Honor `.gitignore` and a dedicated `.gimhubignore` file. 4. Deny known-sensitive filenames and extensions, including credential stores, private keys, environment files, logs, databases, session records, and deployment secrets. 5. Add secret scanning and high-entropy token detection before constructing the request. 6. Display the complete upload list and require confirmation before recursive uploads, particularly in interactive sessions. 7. Use repository-relative paths rather than arbitrary local path strings. 8. Document clearly that selected file contents are transmitted to a remote service. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/gimhub.py:12
Finding
Bearer Tokens and Uploaded Data Can Be Redirected Through an Unvalidated API Base URL<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gimhub.py:12, 32-41` **Vulnerability Type**: Unvalidated security-sensitive endpoint override **Risk Level**: High ### Vulnerable Code ```python GIMHUB_URL = os.environ.get("GIMHUB_URL", "https://gimhub.dev") GIMHUB_TOKEN = os.environ.get("GIMHUB_TOKEN", "") GIMHUB_AGENT = os.environ.get("GIMHUB_AGENT", "") ``` ```python def api_request(method, endpoint, data=None, token=None): """Make API request to GIMHub.""" url = f"{GIMHUB_URL}{endpoint}" headers = {"Content-Type": "application/json"} if token: headers["Authorization"] = f"Bearer {token}" body = json.dumps(data).encode() if data else None req = Request(url, data=body, headers=headers, method=method) try: with urlopen(req) as resp: return json.loads(resp.read().decode()) ``` ### Technical Analysis The destination for all API traffic is controlled by the `GIMHUB_URL` environment variable. The value is not restricted to the documented `https://gimhub.dev` origin, and the implementation does not enforce HTTPS, validate an allowlisted hostname, or require explicit confirmation for a custom server. Authenticated operations attach the GIMHub bearer token to requests sent to this configurable destination. The same mechanism transmits repository file contents, issue content, registration information, verification codes, and proof URLs. Environment variables are legitimate configuration mechanisms, but allowing an ambient variable to silently redefine a credential recipient creates a security boundary failure. A malicious wrapper, poisoned execution environment, compromised automation configuration, or inadvertent environment setting could redirect sensitive requests. ### Attack Path 1. An attacker or compromised launcher sets `GIMHUB_URL` to an attacker-controlled URL before the CLI starts. 2. The user invokes an authenticated command such as `create`, `push`, or `issue`. 3. The CLI obtai ...[truncated 982 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `GIMHUB_URL` overriding unless custom server support is a documented requirement. 2. If custom servers are necessary, require an explicit command-line option and informed confirmation before sending credentials. 3. Enforce HTTPS and reject URLs containing user information, fragments, unexpected paths, or unsupported schemes. 4. Allowlist the official `gimhub.dev` origin by default. Maintain separate credentials scoped to each approved custom origin. 5. Never automatically reuse an official-service token for a different hostname. 6. Resolve and normalize the URL before validation, and define a safe redirect policy that prevents authorization headers from reaching another origin. 7. Log the destination origin before authenticated requests without logging the token itself. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gimhub.py:26
Finding
API Token Is Persisted in Plaintext Without Explicit Owner-Only Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gimhub.py:26-29, 68-71` **Vulnerability Type**: Insecure credential storage **Risk Level**: Medium ### Vulnerable Code ```python def save_config(config): """Save configuration.""" CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True) CONFIG_PATH.write_text(json.dumps(config, indent=2)) ``` Registration stores the returned token in this configuration: ```python config["token"] = result["api_token"] config["agent"] = result["agent"]["name"] config["verification_code"] = result["verification_code"] save_config(config) ``` ### Technical Analysis The CLI saves the API token and verification code in plaintext at `~/.gimhub/config.json`. It creates the directory and file using default permission behavior determined by the process umask, but does not explicitly enforce owner-only permissions. On a system with a permissive or unusual umask, other local users may be able to read the file. Existing configuration files with insecure permissions are also overwritten without first correcting their mode. The implementation does not use an operating-system credential manager, encryption facility, or secure atomic file-creation pattern. Plaintext configuration storage may be acceptable only when strict filesystem permissions are guaranteed. That guarantee is absent here. ### Attack Path 1. A user registers an agent through the CLI. 2. The server returns an API token and verification code. 3. `save_config` writes those values to `~/.gimhub/config.json`. 4. The resulting permissions are inherited from the runtime environment rather than being explicitly restricted. 5. Another local account or process with filesystem access reads the configuration. 6. The attacker extracts the token and performs GIMHub actions as the registered agent. ### Impact Assessment A local attacker able to read the configuration can impersonate the agent and exercise all privileges granted to the stored to ...[truncated 400 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer an operating-system credential manager or secret store instead of a plaintext JSON file. 2. If file storage is unavoidable, create `~/.gimhub` with mode `0700` and the configuration file with mode `0600`. 3. Correct permissions on existing directories and files before reading or rewriting them. 4. Write updates atomically through a securely created temporary file in the same directory, then replace the destination. 5. Avoid retaining the verification code after it is no longer needed, including on failed or interrupted claim workflows where appropriate. 6. Support environment-only or interactive credential use for environments where persistent storage is undesirable. 7. Document the credential location, required permissions, revocation procedure, and token-rotation process. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (10)

Tainted flow: 'req' from os.environ.get (line 41, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
req = Request(url, data=body, headers=headers, method=method)

    try:
        with urlopen(req) as resp:
            return json.loads(resp.read().decode())
    except HTTPError as e:
        error = json.loads(e.read().decode())
Confidence
95% confidence
Finding
The request target is built from the environment-controlled GIMHUB_URL, and the same request may include the bearer token in the Authorization header. If an attacker can influence environment variables or configuration of the agent runtime, they can redirect API calls and exfiltrate credentials and repository contents to an arbitrary server. In an agent skill that performs code pushes, this context increases the danger because the network request can carry both secrets and user files.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description understates actual behavior by omitting agent registration and identity-claim flows, which involve transmitting identifying data and handling authentication material. Description-behavior mismatches undermine informed consent and make it easier for an agent or user to trigger higher-risk actions than expected.

Memory Manipulation

High
Category
Memory Poisoning
Content
-d '{"description": "New description"}'
```

Archive a repository when it's complete or no longer maintained—don't delete history:
```bash
curl -X PUT https://gimhub.dev/api/repos/$GIMHUB_AGENT/my-project \
  -H "Authorization: Bearer $GIMHUB_TOKEN" \
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill documents network access, environment-variable use, and repository/file modification behavior, but it does not declare any explicit tool scope or permission boundaries. In an agent setting, missing scope metadata increases the chance that the skill is invoked with broader capabilities than users expect, enabling unintended data access or outbound transmission.

External Transmission

Medium
Category
Data Exfiltration
Content
### Step 1: Register

```bash
curl -X POST https://gimhub.dev/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{"name": "my-agent", "display_name": "My Agent", "framework": "claude"}'
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The example claim flow suggests a proof URL containing human-identifying information ('https://github.com/your-human/your-soul') even though the policy text says not to include information about humans. This contradictory guidance can induce privacy leakage by normalizing disclosure of a human-associated identity artifact to an external service.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill includes a repository deletion endpoint without a prominent warning or guardrail about its destructive effect. In agent workflows, destructive APIs should be explicitly labeled because an automated model may execute them based on ambiguous prompts, leading to irreversible code or project loss.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The manifest says the skill is for pushing code to GIMHub, creating repos, managing issues, and publishing releases. This file additionally supports registering a new agent and claiming agent identity via verification URLs, which is a distinct account/identity-management capability not reflected in the stated description.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
code = args.code or config.get("verification_code")
    if not code:
        print("Error: No verification code. Register first or provide --code", file=sys.stderr)
        sys.exit(1)

    proof_url = args.proof_url or input("Proof URL: ")
Confidence
75% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
When --files is omitted, the tool recursively uploads all non-hidden, decodable files in the current directory, excluding only a small ignore set. This can unintentionally transmit source code, credentials in plaintext config files, internal documents, or other sensitive material without a clear confirmation step. In a code-publishing skill, that default behavior materially increases the risk of large-scale data leakage.

Static analysis

No suspicious patterns detected.