Back to skill

Security audit

# key-guard A local MCP server that keeps API keys off Claude's servers. ## Why This Exists When Claude reads a file containing an API key, the raw key content gets sent to Claude's servers. key-guard prevents this by acting as a local middleman — Claude calls a tool, the tool reads the key and makes the API call locally, and only the result is returned to Claude.

Security checks for vulnerabilities and agentic risk

Overview

This skill is meant to protect API keys, but its MCP server gives the agent broad, weakly controlled access to credentials, outbound requests, and local file reads/writes.

Review carefully before installing. Only use this in a tightly sandboxed environment with throwaway credentials unless it is changed to restrict allowed key names, approved HTTPS destinations, readable and writable paths, and to require explicit confirmation before any secret-backed request or file write.

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

T09 · Insecure Skill Coding Practices

Error
Location
key-guard.js:80
Finding

Arbitrary Credential Exfiltration and Server-Side Request Forgery

Content
View full analysis
{ const parsed = new URL(url); const lib = parsed.protocol === "https:" ? https : http; const req = lib.request( { ...parsed, method: options.method || "GET", headers: options.headers || {} }, (res) => { let body = ""; res.on("data", (chunk) => (body += chunk)); res.on("end", () => { try { resolve({ status: res.statusCode, body: JSON.parse(body) }); } catch { resolve({ status: res.statusCode, body }); } }); } ); req.on("error", reject); if (options.body) req.write(JSON.stringify(options.body)); req.end(); }); } ``` ```js async function call_api({ key_name, url, method = "GET", headers = {}, body }) { const key = getKey(key_name); if (!key) return { error: `Key '${key_name}' not found` }; // Inject key into Authorization header (adapt pattern as needed) const authHeaders = { Authorization: `Bearer ${key}`, ...headers }; try { const result = await request(url, { method, headers: authHeaders, body }); // Return API result — raw key was never sent to Claude return { status: result.status, data: result.body }; } catch (err) { return { error: err.message }; } } ``` ### Technical Analysis The MCP caller controls both `key_name` and `url`. `getKey()` can retrieve values not only from the project's configured key sources, but also from arbitrary variables in `process.env`. The selected value is the ...[truncated 1688 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
key-guard.js:119
Finding

Unrestricted Arbitrary File Read with Incomplete Secret Masking

Content
View full analysis
= 8) { content = content.split(value).join(`{{${name}}}`); } } return { file_path, content }; } ``` Related secret-source behavior: ```js function loadAllKeys() { // Priority: shell profiles (lowest) → .env → process.env (highest) return { ...loadShellProfileKeys(), ...loadEnv() }; } function getKey(name) { const all = loadAllKeys(); return all[name] || process.env[name] || null; } ``` ### Technical Analysis `path.resolve(file_path)` normalizes the supplied path but does not restrict it to the project or another authorized directory. Absolute paths and traversal sequences can therefore reference any readable file available to the MCP process. There are also no checks for symbolic links that resolve outside an intended workspace. The masking mechanism only replaces values returned by `loadAllKeys()`, which includes `.env` entries and `KG_*` shell-profile entries. It does not include general `process.env` values even though those values are treated as secrets by `getKey()`. Values shorter than eight characters are intentionally not masked. Files containing credentials from other stores or formats are returned unchanged. ### Attack Path 1. An attacker influences the agent to invoke `read_file_masked`. 2. The attacker supplies an absolute sensitive path or a relative path that escapes the project directory. 3. The MCP process resolves and reads the target using its own operating-system p ...[truncated 621 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
key-guard.js:132
Finding

Unrestricted Arbitrary File Overwrite and Secret Materialization

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
key-guard.js:108
Finding

Partial API Key Disclosure Through Validation Metadata

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
README.md:50
Finding

Setup Command Overwrites Existing MCP Configuration

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (27)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

1. Add your keys

bash
cp .env.example .env
# Edit .env with your real API keys

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill is presented as a guardrail, but it also enables credential discovery, partial secret disclosure, arbitrary masked file reads, and writing files with real secret substitution. That mismatch is dangerous because users and reviewers may trust it as purely protective while it actually expands the agent's ability to enumerate secrets and place them into executable files or outbound API calls.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
---
name: key-guard
description: "Security guardrail: prevents API keys from being sent to Claude. Triggers when user asks to call an external API, use a key, check credentials, read .env files, or view/edit scripts that may contain hardcoded keys. Always routes key usage through the local MCP server instead."
---

# Key Guard

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
---
name: key-guard
description: "Security guardrail: prevents API keys from being sent to Claude. Triggers when user asks to call an external API, use a key, check credentials, read .env files, or view/edit scripts that may contain hardcoded keys. Always routes key usage through the local MCP server instead."
---

# Key Guard

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
---
name: key-guard
description: "Security guardrail: prevents API keys from being sent to Claude. Triggers when user asks to call an external API, use a key, check credentials, read .env files, or view/edit scripts that may contain hardcoded keys. Always routes key usage through the local MCP server instead."
---

# Key Guard

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
---
name: key-guard
description: "Security guardrail: prevents API keys from being sent to Claude. Triggers when user asks to call an external API, use a key, check credentials, read .env files, or view/edit scripts that may contain hardcoded keys. Always routes key usage through the local MCP server instead."
---

# Key Guard

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
---
name: key-guard
description: "Security guardrail: prevents API keys from being sent to Claude. Triggers when user asks to call an external API, use a key, check credentials, read .env files, or view/edit scripts that may contain hardcoded keys. Always routes key usage through the local MCP server instead."
---

# Key Guard

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
---
name: key-guard
description: "Security guardrail: prevents API keys from being sent to Claude. Triggers when user asks to call an external API, use a key, check credentials, read .env files, or view/edit scripts that may contain hardcoded keys. Always routes key usage through the local MCP server instead."
---

# Key Guard

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
---
name: key-guard
description: "Security guardrail: prevents API keys from being sent to Claude. Triggers when user asks to call an external API, use a key, check credentials, read .env files, or view/edit scripts that may contain hardcoded keys. Always routes key usage through the local MCP server instead."
---

# Key Guard

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · key-guard.js (reported line 5)May include surrounding context.

js
---
name: key-guard
description: "Security guardrail: prevents API keys from being sent to Claude. Triggers when user asks to call an external API, use a key, check credentials, read .env files, or view/edit scripts that may contain hardcoded keys. Always routes key usage through the local MCP server instead."
---

# Key Guard

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · key-guard.js (reported line 74)May include surrounding context.

js
---
name: key-guard
description: "Security guardrail: prevents API keys from being sent to Claude. Triggers when user asks to call an external API, use a key, check credentials, read .env files, or view/edit scripts that may contain hardcoded keys. Always routes key usage through the local MCP server instead."
---

# Key Guard

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · key-guard.js (reported line 171)May include surrounding context.

js
---
name: key-guard
description: "Security guardrail: prevents API keys from being sent to Claude. Triggers when user asks to call an external API, use a key, check credentials, read .env files, or view/edit scripts that may contain hardcoded keys. Always routes key usage through the local MCP server instead."
---

# Key Guard

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · key-guard.js (reported line 175)May include surrounding context.

js
---
name: key-guard
description: "Security guardrail: prevents API keys from being sent to Claude. Triggers when user asks to call an external API, use a key, check credentials, read .env files, or view/edit scripts that may contain hardcoded keys. Always routes key usage through the local MCP server instead."
---

# Key Guard

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Returning which keys exist and their approximate lengths creates credential metadata leakage that can aid attackers in enumerating installed providers, validating guessed secret types, and profiling the environment. In a guardrail skill, even partial secret disclosure undermines the stated goal of minimizing key exposure.

Content

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

User: "Show me my .env file"

text
Do NOT read .env directly.
Instead, call validate_key for each expected key name and show:
- Which keys are configured
- Approximate length (as a sanity check)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · key-guard.js (reported line 27)May include surrounding context.

js
// ── Config ────────────────────────────────────────────────────────────────────

const ENV_FILE = path.resolve(__dirname, ".env");

// Shell profile files to scan for KG_* keys, in priority order (last wins before .env)
const SHELL_PROFILES = [

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

write_file_with_keys allows arbitrary local file writes to any resolved path and substitutes real secret values into the written content. This can be abused to persist credentials into source files, shell startup files, cron jobs, or other sensitive locations, causing secret leakage, privilege abuse, or durable compromise of the host environment.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill invokes credential- and file-related capabilities but declares no explicit tool scope or allowed-tools boundary. In a security-oriented skill, missing least-privilege constraints increases the chance that the agent can access broader resources than intended, especially around secrets and local files.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 49)May include surrounding context.

text
Call: call_api({
  key_name: "OPENAI_API_KEY",
  url: "https://api.openai.com/v1/models",
  method: "GET"
})
Returns: { status: 200, data: { ... API response ... } }

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 112)May include surrounding context.

text
Call: call_api({
  key_name: "OPENAI_API_KEY",
  url: "https://api.openai.com/v1/models",
  method: "GET"
})
Returns: { status: 200, data: { ... API response ... } }

Session Persistence

Medium
Category
Rogue Agent
Confidence
93% confidence
Finding

The skill can persist real secrets into arbitrary files by substituting placeholders during writeback. This creates a durable secret-exposure path: credentials may end up in scripts, configs, backups, logs, or repositories, and can then be accessed by unrelated processes or later exfiltrated.

Content

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

You can now safely view and suggest edits to the non-key parts.

Tool 4: write_file_with_keys

Write a file back after editing, with {{KEY_NAME}} placeholders substituted with real key values locally.

text
Call: write_file_with_keys({
  file_path: "./call.sh",

External Transmission

Medium
Category
Data Exfiltration
Confidence
84% confidence
Finding

This workflow writes a script containing a real credential substituted locally, which can later be executed to transmit the secret to an external service. Even if Claude never sees the key, the skill materially enables persistence and reuse of secrets in files, increasing the risk of accidental disclosure, source control leaks, or misuse by other tools/processes.

Content

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

text
Call: write_file_with_keys({
  file_path: "./call.sh",
  content: "curl -H 'Authorization: Bearer {{OPENAI_API_KEY}}' https://api.openai.com/v1/chat/completions ..."
})
Returns: { success: true, message: "File written with keys substituted locally" }

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill silently scans .env and user shell profile files for secrets without any user-facing warning or confirmation. In an LLM-tooling context, this is dangerous because a prompt-injected or overly broad task can trigger credential discovery and subsequent use of local secrets without the user realizing sensitive sources were accessed.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill’s stated purpose is to prevent key exposure to Claude, but it also exposes broader capabilities: enumerating local key names and performing arbitrary file read/write operations. Those extra capabilities materially expand the attack surface and enable an LLM or prompt-injected workflow to inspect sensitive local files or manipulate files while leveraging locally stored secrets.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

read_file_masked permits reading any local file path, far beyond what is needed for a key-routing guardrail. Although it attempts to mask known key values, masking is incomplete because only currently loaded secrets of length >= 8 are replaced, so unrelated credentials, short secrets, tokens in alternate formats, and other sensitive local data can still be exposed to Claude.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

Writing arbitrary files with live secret substitution happens with no approval step or warning to the user. This combination is especially risky because it can quietly materialize credentials into files that are later committed, logged, served, or executed, turning a temporary secret into a durable exposure or persistence mechanism.

Content

No source excerpt is available for this finding.