mcp-security-audit

작성자: github

MCP 서버 구성을 감사하여 보안 문제(비밀 노출, 셸 인젝션, 고정되지 않은 종속성, 승인되지 않은 서버)를 점검합니다.

npx skills add https://github.com/github/awesome-copilot --skill mcp-security-audit

MCP Security Audit

Audit MCP server configurations for security issues — secrets exposure, shell injection, unpinned dependencies, and unapproved servers.

Overview

MCP servers give agents direct tool access to external systems. A misconfigured .mcp.json can expose credentials, allow shell injection, or connect to untrusted servers. This skill catches those issues before they reach production.

.mcp.json → Parse Servers → Check Each Server:
  1. Secrets in args/env?
  2. Shell injection patterns?
  3. Unpinned versions (@latest)?
  4. Dangerous commands (eval, bash -c)?
  5. Server on approved list?
→ Generate Report

When to Use

  • Reviewing any .mcp.json file in a project
  • Onboarding a new MCP server to a project
  • Auditing all MCP servers in a monorepo or plugin marketplace
  • Pre-commit checks for MCP configuration changes
  • Security review of agent tool configurations

Audit Check 1: Hardcoded Secrets

Scan MCP server args and env values for hardcoded credentials.

import json
import re
from pathlib import Path

SECRET_PATTERNS = [
    (r'(?i)(api[_-]?key|token|secret|password|credential)\s*[:=]\s*["\'][^"\']{8,}', "Hardcoded secret"),
    (r'(?i)Bearer\s+[A-Za-z0-9\-._~+/]+=*', "Hardcoded bearer token"),
    (r'(?i)(ghp_|gho_|ghu_|ghs_|ghr_)[A-Za-z0-9]{30,}', "GitHub token"),
    (r'sk-[A-Za-z0-9]{20,}', "OpenAI API key"),
    (r'AKIA[0-9A-Z]{16}', "AWS access key"),
    (r'-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----', "Private key"),
]

def check_secrets(mcp_config: dict) -> list[dict]:
    """Check for hardcoded secrets in MCP server configurations."""
    findings = []
    raw = json.dumps(mcp_config)
    for pattern, description in SECRET_PATTERNS:
        matches = re.findall(pattern, raw)
        if matches:
            findings.append({
                "severity": "CRITICAL",
                "check": "hardcoded-secret",
                "message": f"{description} found in MCP configuration",
                "evidence": f"Pattern matched: {pattern}",
                "fix": "Use environment variable references: ${ENV_VAR_NAME}"
            })
    return findings

Good practice — use env var references:

{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["server.js"],
      "env": {
        "API_KEY": "${MY_API_KEY}",
        "DB_URL": "${DATABASE_URL}"
      }
    }
  }
}

Bad — hardcoded credentials:

{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["server.js", "--api-key", "sk-abc123realkey456"],
      "env": {
        "DB_URL": "postgresql://admin:password123@prod-db:5432/main"
      }
    }
  }
}

Audit Check 2: Shell Injection Patterns

Detect dangerous command patterns in MCP server args.

import json
import re

DANGEROUS_PATTERNS = [
    (r'\$\(', "Command substitution $(...)"),
    (r'`[^`]+`', "Backtick command substitution"),
    (r';\s*\w', "Command chaining with semicolon"),
    (r'\|\s*\w', "Pipe to another command"),
    (r'&&\s*\w', "Command chaining with &&"),
    (r'\|\|\s*\w', "Command chaining with ||"),
    (r'(?i)eval\s', "eval usage"),
    (r'(?i)bash\s+-c\s', "bash -c execution"),
    (r'(?i)sh\s+-c\s', "sh -c execution"),
    (r'>\s*/dev/tcp/', "TCP redirect (reverse shell pattern)"),
    (r'curl\s+.*\|\s*(ba)?sh', "curl pipe to shell"),
]

def check_shell_injection(server_config: dict) -> list[dict]:
    """Check MCP server args for shell injection risks."""
    findings = []
    args_text = json.dumps(server_config.get("args", []))
    for pattern, description in DANGEROUS_PATTERNS:
        if re.search(pattern, args_text):
            findings.append({
                "severity": "HIGH",
                "check": "shell-injection",
                "message": f"Dangerous pattern in MCP server args: {description}",
                "fix": "Use direct command execution, not shell interpolation"
            })
    return findings

Audit Check 3: Unpinned Dependencies

Flag MCP servers using @latest in their package references.

def check_pinned_versions(server_config: dict) -> list[dict]:
    """Check that MCP server dependencies use pinned versions, not @latest."""
    findings = []
    args = server_config.get("args", [])
    for arg in args:
        if isinstance(arg, str):
            if "@latest" in arg:
                findings.append({
                    "severity": "MEDIUM",
                    "check": "unpinned-dependency",
                    "message": f"Unpinned dependency: {arg}",
                    "fix": f"Pin to specific version: {arg.replace('@latest', '@1.2.3')}"
                })
            # npx with unversioned package
            if arg.startswith("-y") or (not "@" in arg and not arg.startswith("-")):
                pass  # npx flag or plain arg, ok
    # Check if using npx without -y (interactive prompt in CI)
    command = server_config.get("command", "")
    if command == "npx" and "-y" not in args:
        findings.append({
            "severity": "LOW",
            "check": "npx-interactive",
            "message": "npx without -y flag may prompt interactively in CI",
            "fix": "Add -y flag: npx -y package-name"
        })
    return findings

Good — pinned version:

{ "args": ["-y", "[email protected]"] }

Bad — unpinned:

{ "args": ["-y", "my-mcp-server@latest"] }

Audit Check 4: Full Audit Runner

Combine all checks into a single audit.

def audit_mcp_config(mcp_path: str) -> dict:
    """Run full security audit on an .mcp.json file."""
    path = Path(mcp_path)
    if not path.exists():
        return {"error": f"{mcp_path} not found"}

    config = json.loads(path.read_text(encoding="utf-8"))
    servers = config.get("mcpServers", {})
    results = {"file": str(path), "servers": {}, "summary": {}}
    total_findings = []

    # Run secrets check once on the whole config (not per-server)
    config_level_findings = check_secrets(config)
    total_findings.extend(config_level_findings)

    for name, server_config in servers.items():
        if not isinstance(server_config, dict):
            continue
        findings = []
        findings.extend(check_shell_injection(server_config))
        findings.extend(check_pinned_versions(server_config))
        results["servers"][name] = {
            "command": server_config.get("command", ""),
            "findings": findings,
        }
        total_findings.extend(findings)

    # Summary
    by_severity = {}
    for f in total_findings:
        sev = f["severity"]
        by_severity[sev] = by_severity.get(sev, 0) + 1

    results["summary"] = {
        "total_servers": len(servers),
        "total_findings": len(total_findings),
        "by_severity": by_severity,
        "passed": len(total_findings) == 0,
    }
    return results

Usage:

results = audit_mcp_config(".mcp.json")
if not results["summary"]["passed"]:
    for server, data in results["servers"].items():
        for finding in data["findings"]:
            print(f"[{finding['severity']}] {server}: {finding['message']}")
            print(f"  Fix: {finding['fix']}")

Output Format

MCP Security Audit — .mcp.json
═══════════════════════════════
Servers scanned: 5
Findings: 3 (1 CRITICAL, 1 HIGH, 1 MEDIUM)

[CRITICAL] my-api-server: Hardcoded secret found in MCP configuration
  Fix: Use environment variable references: ${ENV_VAR_NAME}

[HIGH] data-processor: Dangerous pattern in MCP server args: bash -c execution
  Fix: Use direct command execution, not shell interpolation

[MEDIUM] analytics: Unpinned dependency: analytics-mcp@latest
  Fix: Pin to specific version: [email protected]

Related Resources

github의 다른 스킬

console-rendering
github
Go에서 struct 태그 기반 콘솔 렌더링 시스템 사용 지침
official
acquire-codebase-knowledge
github
사용자가 기존 코드베이스에 대한 매핑, 문서화, 또는 온보딩을 명시적으로 요청할 때 이 스킬을 사용하세요. "이 코드베이스를 매핑해줘", "문서화해줘"와 같은 프롬프트에서 트리거됩니다.
official
acreadiness-assess
github
현재 리포
official
acreadiness-generate-instructions
github
AgentRC 명령어를 통해 맞춤형 AI 에이전트 지침 파일을 생성합니다. .github/copilot-instructions.md 파일을 생성합니다(기본값, VS Code의 Copilot에 권장됨).
official
acreadiness-policy
github
사용자가 AgentRC 정책을 선택, 작성 또는 적용할 수 있도록 지원합니다. 정책은 관련 없는 검사를 비활성화하고, 영향/수준을 재정의하며, 설정을 통해 준비 상태 점수를 사용자 지정합니다.
official
add-educational-comments
github
코드 파일에 교육용 주석을 추가하여 효과적인 학습 자료로 변환합니다. 설명의 깊이와 어조를 세 가지 설정 가능한 지식 수준(초급, 중급, 고급)에 맞게 조정합니다. 파일이 제공되지 않으면 자동으로 요청하며, 빠른 선택을 위해 번호 목록 매칭을 제공합니다. 교육용 주석만을 사용하여 파일을 최대 125%까지 확장합니다(엄격한 제한: 새 줄 400개, 1,000줄 초과 파일의 경우 300개). 파일 인코딩, 들여쓰기 스타일, 구문 정확성 등을 유지합니다.
official
adobe-illustrator-scripting
github
Adobe Illustrator 자동화 스크립트를 ExtendScript(JavaScript/JSX)로 작성, 디버깅 및 최적화합니다. 스크립트를 생성하거나 수정하여 조작할 때 사용합니다.
official
agent-governance
github
선언적 정책, 의도 분류, AI 에이전트 도구 접근 및 행동 제어를 위한 감사 추적. 구성 가능한 거버넌스 정책은 허용/차단된 도구, 콘텐츠 필터, 속도 제한, 승인 요구 사항을 정의하며, 코드가 아닌 구성으로 저장됨. 의미론적 의도 분류는 패턴 기반 신호를 사용하여 도구 실행 전에 위험한 프롬프트(데이터 유출, 권한 상승, 프롬프트 인젝션)를 탐지함. 도구 수준 거버넌스 데코레이터는 함수에서 정책을 적용함...
official