{"id":"ee9ec977-b50b-43af-92fa-d61c2ea8ec2b","shortId":"QLwQmy","kind":"skill","title":"mcp-security-audit","tagline":"Audit MCP (Model Context Protocol) server configurations for security issues. Use this skill when:\n- Reviewing .mcp.json files for security risks\n- Checking MCP server args for hardcoded secrets or shell injection patterns\n- Validating that MCP servers use pinned versions (not @l","description":"# MCP Security Audit\n\nAudit MCP server configurations for security issues — secrets exposure, shell injection, unpinned dependencies, and unapproved servers.\n\n## Overview\n\nMCP 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.\n\n```\n.mcp.json → Parse Servers → Check Each Server:\n  1. Secrets in args/env?\n  2. Shell injection patterns?\n  3. Unpinned versions (@latest)?\n  4. Dangerous commands (eval, bash -c)?\n  5. Server on approved list?\n→ Generate Report\n```\n\n## When to Use\n\n- Reviewing any `.mcp.json` file in a project\n- Onboarding a new MCP server to a project\n- Auditing all MCP servers in a monorepo or plugin marketplace\n- Pre-commit checks for MCP configuration changes\n- Security review of agent tool configurations\n\n---\n\n## Audit Check 1: Hardcoded Secrets\n\nScan MCP server args and env values for hardcoded credentials.\n\n```python\nimport json\nimport re\nfrom pathlib import Path\n\nSECRET_PATTERNS = [\n    (r'(?i)(api[_-]?key|token|secret|password|credential)\\s*[:=]\\s*[\"\\'][^\"\\']{8,}', \"Hardcoded secret\"),\n    (r'(?i)Bearer\\s+[A-Za-z0-9\\-._~+/]+=*', \"Hardcoded bearer token\"),\n    (r'(?i)(ghp_|gho_|ghu_|ghs_|ghr_)[A-Za-z0-9]{30,}', \"GitHub token\"),\n    (r'sk-[A-Za-z0-9]{20,}', \"OpenAI API key\"),\n    (r'AKIA[0-9A-Z]{16}', \"AWS access key\"),\n    (r'-----BEGIN\\s+(RSA\\s+)?PRIVATE\\s+KEY-----', \"Private key\"),\n]\n\ndef check_secrets(mcp_config: dict) -> list[dict]:\n    \"\"\"Check for hardcoded secrets in MCP server configurations.\"\"\"\n    findings = []\n    raw = json.dumps(mcp_config)\n    for pattern, description in SECRET_PATTERNS:\n        matches = re.findall(pattern, raw)\n        if matches:\n            findings.append({\n                \"severity\": \"CRITICAL\",\n                \"check\": \"hardcoded-secret\",\n                \"message\": f\"{description} found in MCP configuration\",\n                \"evidence\": f\"Pattern matched: {pattern}\",\n                \"fix\": \"Use environment variable references: ${ENV_VAR_NAME}\"\n            })\n    return findings\n```\n\n**Good practice — use env var references:**\n```json\n{\n  \"mcpServers\": {\n    \"my-server\": {\n      \"command\": \"node\",\n      \"args\": [\"server.js\"],\n      \"env\": {\n        \"API_KEY\": \"${MY_API_KEY}\",\n        \"DB_URL\": \"${DATABASE_URL}\"\n      }\n    }\n  }\n}\n```\n\n**Bad — hardcoded credentials:**\n```json\n{\n  \"mcpServers\": {\n    \"my-server\": {\n      \"command\": \"node\",\n      \"args\": [\"server.js\", \"--api-key\", \"sk-abc123realkey456\"],\n      \"env\": {\n        \"DB_URL\": \"postgresql://admin:password123@prod-db:5432/main\"\n      }\n    }\n  }\n}\n```\n\n---\n\n## Audit Check 2: Shell Injection Patterns\n\nDetect dangerous command patterns in MCP server args.\n\n```python\nimport json\nimport re\n\nDANGEROUS_PATTERNS = [\n    (r'\\$\\(', \"Command substitution $(...)\"),\n    (r'`[^`]+`', \"Backtick command substitution\"),\n    (r';\\s*\\w', \"Command chaining with semicolon\"),\n    (r'\\|\\s*\\w', \"Pipe to another command\"),\n    (r'&&\\s*\\w', \"Command chaining with &&\"),\n    (r'\\|\\|\\s*\\w', \"Command chaining with ||\"),\n    (r'(?i)eval\\s', \"eval usage\"),\n    (r'(?i)bash\\s+-c\\s', \"bash -c execution\"),\n    (r'(?i)sh\\s+-c\\s', \"sh -c execution\"),\n    (r'>\\s*/dev/tcp/', \"TCP redirect (reverse shell pattern)\"),\n    (r'curl\\s+.*\\|\\s*(ba)?sh', \"curl pipe to shell\"),\n]\n\ndef check_shell_injection(server_config: dict) -> list[dict]:\n    \"\"\"Check MCP server args for shell injection risks.\"\"\"\n    findings = []\n    args_text = json.dumps(server_config.get(\"args\", []))\n    for pattern, description in DANGEROUS_PATTERNS:\n        if re.search(pattern, args_text):\n            findings.append({\n                \"severity\": \"HIGH\",\n                \"check\": \"shell-injection\",\n                \"message\": f\"Dangerous pattern in MCP server args: {description}\",\n                \"fix\": \"Use direct command execution, not shell interpolation\"\n            })\n    return findings\n```\n\n---\n\n## Audit Check 3: Unpinned Dependencies\n\nFlag MCP servers using `@latest` in their package references.\n\n```python\ndef check_pinned_versions(server_config: dict) -> list[dict]:\n    \"\"\"Check that MCP server dependencies use pinned versions, not @latest.\"\"\"\n    findings = []\n    args = server_config.get(\"args\", [])\n    for arg in args:\n        if isinstance(arg, str):\n            if \"@latest\" in arg:\n                findings.append({\n                    \"severity\": \"MEDIUM\",\n                    \"check\": \"unpinned-dependency\",\n                    \"message\": f\"Unpinned dependency: {arg}\",\n                    \"fix\": f\"Pin to specific version: {arg.replace('@latest', '@1.2.3')}\"\n                })\n            # npx with unversioned package\n            if arg.startswith(\"-y\") or (not \"@\" in arg and not arg.startswith(\"-\")):\n                pass  # npx flag or plain arg, ok\n    # Check if using npx without -y (interactive prompt in CI)\n    command = server_config.get(\"command\", \"\")\n    if command == \"npx\" and \"-y\" not in args:\n        findings.append({\n            \"severity\": \"LOW\",\n            \"check\": \"npx-interactive\",\n            \"message\": \"npx without -y flag may prompt interactively in CI\",\n            \"fix\": \"Add -y flag: npx -y package-name\"\n        })\n    return findings\n```\n\n**Good — pinned version:**\n```json\n{ \"args\": [\"-y\", \"my-mcp-server@2.1.0\"] }\n```\n\n**Bad — unpinned:**\n```json\n{ \"args\": [\"-y\", \"my-mcp-server@latest\"] }\n```\n\n---\n\n## Audit Check 4: Full Audit Runner\n\nCombine all checks into a single audit.\n\n```python\ndef audit_mcp_config(mcp_path: str) -> dict:\n    \"\"\"Run full security audit on an .mcp.json file.\"\"\"\n    path = Path(mcp_path)\n    if not path.exists():\n        return {\"error\": f\"{mcp_path} not found\"}\n\n    config = json.loads(path.read_text(encoding=\"utf-8\"))\n    servers = config.get(\"mcpServers\", {})\n    results = {\"file\": str(path), \"servers\": {}, \"summary\": {}}\n    total_findings = []\n\n    # Run secrets check once on the whole config (not per-server)\n    config_level_findings = check_secrets(config)\n    total_findings.extend(config_level_findings)\n\n    for name, server_config in servers.items():\n        if not isinstance(server_config, dict):\n            continue\n        findings = []\n        findings.extend(check_shell_injection(server_config))\n        findings.extend(check_pinned_versions(server_config))\n        results[\"servers\"][name] = {\n            \"command\": server_config.get(\"command\", \"\"),\n            \"findings\": findings,\n        }\n        total_findings.extend(findings)\n\n    # Summary\n    by_severity = {}\n    for f in total_findings:\n        sev = f[\"severity\"]\n        by_severity[sev] = by_severity.get(sev, 0) + 1\n\n    results[\"summary\"] = {\n        \"total_servers\": len(servers),\n        \"total_findings\": len(total_findings),\n        \"by_severity\": by_severity,\n        \"passed\": len(total_findings) == 0,\n    }\n    return results\n```\n\n**Usage:**\n```python\nresults = audit_mcp_config(\".mcp.json\")\nif not results[\"summary\"][\"passed\"]:\n    for server, data in results[\"servers\"].items():\n        for finding in data[\"findings\"]:\n            print(f\"[{finding['severity']}] {server}: {finding['message']}\")\n            print(f\"  Fix: {finding['fix']}\")\n```\n\n---\n\n## Output Format\n\n```\nMCP Security Audit — .mcp.json\n═══════════════════════════════\nServers scanned: 5\nFindings: 3 (1 CRITICAL, 1 HIGH, 1 MEDIUM)\n\n[CRITICAL] my-api-server: Hardcoded secret found in MCP configuration\n  Fix: Use environment variable references: ${ENV_VAR_NAME}\n\n[HIGH] data-processor: Dangerous pattern in MCP server args: bash -c execution\n  Fix: Use direct command execution, not shell interpolation\n\n[MEDIUM] analytics: Unpinned dependency: analytics-mcp@latest\n  Fix: Pin to specific version: analytics-mcp@2.1.0\n```\n\n---\n\n## Related Resources\n\n- [MCP Specification](https://modelcontextprotocol.io/)\n- [Agent Governance Toolkit](https://github.com/microsoft/agent-governance-toolkit) — Full governance framework with MCP trust proxy\n- [OWASP ASI-02: Insecure Tool Use](https://owasp.org/www-project-agentic-ai-threats/)","tags":["mcp","security","audit","awesome","copilot","github","agent-skills","agents","custom-agents","github-copilot","hacktoberfest","prompt-engineering"],"capabilities":["skill","source-github","skill-mcp-security-audit","topic-agent-skills","topic-agents","topic-awesome","topic-custom-agents","topic-github-copilot","topic-hacktoberfest","topic-prompt-engineering"],"categories":["awesome-copilot"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/github/awesome-copilot/mcp-security-audit","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add github/awesome-copilot","source_repo":"https://github.com/github/awesome-copilot","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 30743 github stars · SKILL.md body (8,076 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-22T00:52:12.513Z","embedding":null,"createdAt":"2026-04-18T21:50:09.307Z","updatedAt":"2026-04-22T00:52:12.513Z","lastSeenAt":"2026-04-22T00:52:12.513Z","tsv":"'-02':993 '-8':751 '-9':251 '/)':977 '/dev/tcp':463 '/microsoft/agent-governance-toolkit)':983 '/www-project-agentic-ai-threats/)':999 '0':250,837,858 '1':104,173,838,908,910,912 '1.2.3':609 '16':255 '2':108,385 '2.1.0':690,970 '20':244 '3':112,541,907 '30':234 '4':116,703 '5':122,905 '5432/main':382 '8':207 '9':218,233,243 'a-z':252 'a-za-z0':214,229,239 'abc123realkey456':373 'access':71,257 'add':670 'admin':377 'agent':68,168,978 'akia':249 'allow':81 'analyt':955,959,968 'analytics-mcp':958,967 'anoth':423 'api':199,246,347,350,369,917 'api-key':368 'approv':125 'arg':28,179,344,366,396,491,497,501,511,527,574,576,578,580,583,588,600,620,629,651,684,694,942 'arg.replace':607 'arg.startswith':615,623 'args/env':107 'asi':992 'audit':4,5,47,48,147,171,383,539,701,705,713,716,726,864,901 'aw':256 'ba':473 'backtick':408 'bad':356,691 'bash':120,445,449,943 'bearer':212,220 'begin':260 'by_severity.get':835 'c':121,447,450,456,459,944 'catch':91 'chain':415,429,435 'chang':164 'check':25,101,160,172,270,277,305,384,480,488,516,540,555,563,592,631,655,702,709,765,778,800,806 'ci':640,668 'combin':707 'command':118,342,364,391,405,409,414,424,428,434,532,641,643,645,814,816,949 'commit':159 'config':273,289,484,559,718,745,770,775,780,782,788,795,804,810,866 'config.get':753 'configur':11,51,163,170,284,315,924 'connect':85 'context':8 'continu':797 'credenti':80,185,204,358 'critic':304,909,914 'curl':470,475 'danger':117,390,402,506,522,937 'data':875,883,935 'data-processor':934 'databas':354 'db':352,375,381 'def':269,479,554,715 'depend':60,543,567,595,599,957 'descript':292,311,504,528 'detect':389 'dict':274,276,485,487,560,562,722,796 'direct':69,531,948 'encod':749 'env':181,326,334,346,374,930 'environ':323,927 'error':739 'eval':119,439,441 'evid':316 'execut':451,460,533,945,950 'expos':79 'exposur':56 'extern':73 'f':310,317,521,597,602,740,825,830,886,893 'file':21,135,730,756 'find':285,330,496,538,573,679,762,777,784,798,817,818,820,828,846,849,857,881,884,887,890,895,906 'findings.append':302,513,589,652 'findings.extend':799,805 'fix':321,529,601,669,894,896,925,946,962 'flag':544,626,663,672 'format':898 'found':312,744,921 'framework':986 'full':704,724,984 'generat':127 'gho':225 'ghp':224 'ghr':228 'ghs':227 'ghu':226 'github':235 'github.com':982 'github.com/microsoft/agent-governance-toolkit)':981 'give':67 'good':331,680 'govern':979,985 'hardcod':30,174,184,208,219,279,307,357,919 'hardcoded-secret':306 'high':515,911,933 'import':187,189,193,398,400 'inject':34,58,83,110,387,482,494,519,802 'insecur':994 'interact':637,658,666 'interpol':536,953 'isinst':582,793 'issu':14,54,93 'item':879 'json':188,337,359,399,683,693 'json.dumps':287,499 'json.loads':746 'key':200,247,258,266,268,348,351,370 'l':44 'latest':115,548,572,586,608,700,961 'len':843,847,855 'level':776,783 'list':126,275,486,561 'low':654 'marketplac':156 'match':296,301,319 'may':664 'mcp':2,6,26,38,45,49,65,142,149,162,177,272,282,288,314,394,489,525,545,565,688,698,717,719,733,741,865,899,923,940,960,969,973,988 'mcp-security-audit':1 'mcp.json':20,77,98,134,729,867,902 'mcpserver':338,360,754 'medium':591,913,954 'messag':309,520,596,659,891 'misconfigur':76 'model':7 'modelcontextprotocol.io':976 'modelcontextprotocol.io/)':975 'monorepo':153 'my-api-serv':915 'my-mcp-serv':686,696 'my-serv':339,361 'name':328,677,786,813,932 'new':141 'node':343,365 'npx':610,625,634,646,657,660,673 'npx-interact':656 'ok':630 'onboard':139 'openai':245 'output':897 'overview':64 'owasp':991 'owasp.org':998 'owasp.org/www-project-agentic-ai-threats/)':997 'packag':551,613,676 'package-nam':675 'pars':99 'pass':624,854,872 'password':203 'password123':378 'path':194,720,731,732,734,742,758 'path.exists':737 'path.read':747 'pathlib':192 'pattern':35,111,196,291,295,298,318,320,388,392,403,468,503,507,510,523,938 'per':773 'per-serv':772 'pin':41,556,569,603,681,807,963 'pipe':421,476 'plain':628 'plugin':155 'practic':332 'pre':158 'pre-commit':157 'print':885,892 'privat':264,267 'processor':936 'prod':380 'prod-db':379 'product':97 'project':138,146 'prompt':638,665 'protocol':9 'proxi':990 'python':186,397,553,714,862 'r':197,210,222,237,248,259,404,407,411,418,425,431,437,443,452,461,469 'raw':286,299 're':190,401 're.findall':297 're.search':509 'reach':96 'redirect':465 'refer':325,336,552,929 'relat':971 'report':128 'resourc':972 'result':755,811,839,860,863,870,877 'return':329,537,678,738,859 'revers':466 'review':19,132,166 'risk':24,495 'rsa':262 'run':723,763 'runner':706 'scan':176,904 'secret':31,55,105,175,195,202,209,271,280,294,308,764,779,920 'secur':3,13,23,46,53,165,725,900 'semicolon':417 'server':10,27,39,50,63,66,88,100,103,123,143,150,178,283,341,363,395,483,490,526,546,558,566,689,699,752,759,774,787,794,803,809,812,842,844,874,878,889,903,918,941 'server.js':345,367 'server_config.get':500,575,642,815 'servers.items':790 'sev':829,834,836 'sever':303,514,590,653,823,831,833,851,853,888 'sh':454,458,474 'shell':33,57,82,109,386,467,478,481,493,518,535,801,952 'shell-inject':517 'singl':712 'sk':238,372 'sk-abc123realkey456':371 'skill':17,90 'skill-mcp-security-audit' 'source-github' 'specif':605,965,974 'str':584,721,757 'substitut':406,410 'summari':760,821,840,871 'system':74 'tcp':464 'text':498,512,748 'token':201,221,236 'tool':70,169,995 'toolkit':980 'topic-agent-skills' 'topic-agents' 'topic-awesome' 'topic-custom-agents' 'topic-github-copilot' 'topic-hacktoberfest' 'topic-prompt-engineering' 'total':761,827,841,845,848,856 'total_findings.extend':781,819 'trust':989 'unapprov':62 'unpin':59,113,542,594,598,692,956 'unpinned-depend':593 'untrust':87 'unvers':612 'url':353,355,376 'usag':442,861 'use':15,40,131,322,333,530,547,568,633,926,947,996 'utf':750 'valid':36 'valu':182 'var':327,335,931 'variabl':324,928 'version':42,114,557,570,606,682,808,966 'w':413,420,427,433 'whole':769 'without':635,661 'y':616,636,648,662,671,674,685,695 'z':254 'z0':217,232,242 'za':216,231,241","prices":[{"id":"bb52605d-bf62-4dd4-a088-03a031ba82f6","listingId":"ee9ec977-b50b-43af-92fa-d61c2ea8ec2b","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"github","category":"awesome-copilot","install_from":"skills.sh"},"createdAt":"2026-04-18T21:50:09.307Z"}],"sources":[{"listingId":"ee9ec977-b50b-43af-92fa-d61c2ea8ec2b","source":"github","sourceId":"github/awesome-copilot/mcp-security-audit","sourceUrl":"https://github.com/github/awesome-copilot/tree/main/skills/mcp-security-audit","isPrimary":false,"firstSeenAt":"2026-04-18T21:50:09.307Z","lastSeenAt":"2026-04-22T00:52:12.513Z"}],"details":{"listingId":"ee9ec977-b50b-43af-92fa-d61c2ea8ec2b","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"github","slug":"mcp-security-audit","github":{"repo":"github/awesome-copilot","stars":30743,"topics":["agent-skills","agents","ai","awesome","custom-agents","github-copilot","hacktoberfest","prompt-engineering"],"license":"mit","html_url":"https://github.com/github/awesome-copilot","pushed_at":"2026-04-21T22:20:21Z","description":"Community-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.","skill_md_sha":"ef866b906abecd7368d124ce7ebf100c1785f203","skill_md_path":"skills/mcp-security-audit/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/github/awesome-copilot/tree/main/skills/mcp-security-audit"},"layout":"multi","source":"github","category":"awesome-copilot","frontmatter":{"name":"mcp-security-audit","description":"Audit MCP (Model Context Protocol) server configurations for security issues. Use this skill when:\n- Reviewing .mcp.json files for security risks\n- Checking MCP server args for hardcoded secrets or shell injection patterns\n- Validating that MCP servers use pinned versions (not @latest)\n- Detecting unpinned dependencies in MCP server configurations\n- Auditing which MCP servers a project registers and whether they're on an approved list\n- Checking for environment variable usage vs. hardcoded credentials in MCP configs\n- Any request like \"is my MCP config secure?\", \"audit my MCP servers\", or \"check .mcp.json\"\nkeywords: [mcp, security, audit, secrets, shell-injection, supply-chain, governance]"},"skills_sh_url":"https://skills.sh/github/awesome-copilot/mcp-security-audit"},"updatedAt":"2026-04-22T00:52:12.513Z"}}