Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/README.skills.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to
| [mcp-deploy-manage-agents](../skills/mcp-deploy-manage-agents/SKILL.md)<br />`gh skills install github/awesome-copilot mcp-deploy-manage-agents` | Skill converted from mcp-deploy-manage-agents.prompt.md | None |
| [mcp-implementation-security-review](../skills/mcp-implementation-security-review/SKILL.md)<br />`gh skills install github/awesome-copilot mcp-implementation-security-review` | Review the implementation source code of MCP (Model Context Protocol) servers, clients, and tool handlers against a security baseline — authentication, sessions, rate limiting, input-schema validation, official-SDK usage, RCE vectors, and the OWASP MCP Top 10 — producing a report with file/line evidence. Use this skill when:<br />- Reviewing an MCP server implementation for security before release<br />- Checking a server against the baseline controls (MCP-01 to MCP-05) and the OWASP MCP Top 10<br />- Auditing tools for RCE vectors (command/code injection, unsafe deserialization, path traversal, SSTI, dependency hijacking, SSRF)<br />- Verifying auth, session, rate-limiting, and input-validation controls on a network-exposed server<br />- Reviewing MCP client code that handles untrusted server responses and session IDs<br />- Requests like "review this MCP server for security" or "is my MCP server implementation secure?" | None |
| [mcp-release-qa](../skills/mcp-release-qa/SKILL.md)<br />`gh skills install github/awesome-copilot mcp-release-qa` | Verify an MCP server before release by exercising a real protocol session, comparing runtime capabilities with source and documentation, testing failure paths, and recording reproducible evidence. Use when shipping or reviewing an MCP server, tool, resource, prompt, catalog, or install path. | None |
| [mcp-security-audit](../skills/mcp-security-audit/SKILL.md)<br />`gh skills install github/awesome-copilot mcp-security-audit` | Audit MCP (Model Context Protocol) server configurations for security issues. Use this skill when:<br />- Reviewing .mcp.json files for security risks<br />- Checking MCP server args for hardcoded secrets or shell injection patterns<br />- Validating that MCP package-runner dependencies use exact reviewed versions, not bare names, @latest, or ranges<br />- Detecting mutable npm/npx, bunx, pnpm dlx, yarn dlx, and npm exec references in MCP configurations<br />- Auditing which MCP servers a project registers and whether they're on an approved list<br />- Checking for environment variable usage vs. hardcoded credentials in MCP configs<br />- Any request like "is my MCP config secure?", "audit my MCP servers", or "check .mcp.json"<br />keywords: [mcp, security, audit, secrets, shell-injection, supply-chain, governance] | None |
| [mcp-security-audit](../skills/mcp-security-audit/SKILL.md)<br />`gh skills install github/awesome-copilot mcp-security-audit` | Audit MCP (Model Context Protocol) server configurations for security issues. Use this skill when:<br />- Reviewing .mcp.json files for security risks<br />- Checking MCP server args for hardcoded secrets or shell injection patterns<br />- Validating that MCP package-runner dependencies use exact reviewed versions, not bare names, @latest, or ranges<br />- Detecting mutable npm/npx, bunx, pnpm dlx, yarn dlx, npm exec, uvx, uv tool run, and pipx run references in MCP configurations<br />- Auditing which MCP servers a project registers and whether they're on an approved list<br />- Checking for environment variable usage vs. hardcoded credentials in MCP configs<br />- Any request like "is my MCP config secure?", "audit my MCP servers", or "check .mcp.json"<br />keywords: [mcp, security, audit, secrets, shell-injection, supply-chain, governance] | None |
| [md-to-docx](../skills/md-to-docx/SKILL.md)<br />`gh skills install github/awesome-copilot md-to-docx` | Convert Markdown files to professionally formatted Word (.docx) documents with embedded PNG images — pure JavaScript, no external tools required | `scripts/md-to-docx.mjs`<br />`scripts/package.json` |
| [meeting-minutes](../skills/meeting-minutes/SKILL.md)<br />`gh skills install github/awesome-copilot meeting-minutes` | Generate concise, actionable meeting minutes for internal meetings. Includes metadata, attendees, agenda, decisions, action items (owner + due date), and follow-up steps. | None |
| [memory-merger](../skills/memory-merger/SKILL.md)<br />`gh skills install github/awesome-copilot memory-merger` | Merges mature lessons from a domain memory file into its instruction file. Syntax: `/memory-merger >domain [scope]` where scope is `global` (default), `user`, `workspace`, or `ws`. | None |
Expand Down
55 changes: 44 additions & 11 deletions skills/mcp-security-audit/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: |
- Reviewing .mcp.json files for security risks
- Checking MCP server args for hardcoded secrets or shell injection patterns
- Validating that MCP package-runner dependencies use exact reviewed versions, not bare names, @latest, or ranges
- Detecting mutable npm/npx, bunx, pnpm dlx, yarn dlx, and npm exec references in MCP configurations
- Detecting mutable npm/npx, bunx, pnpm dlx, yarn dlx, npm exec, uvx, uv tool run, and pipx run references in MCP configurations
- Auditing which MCP servers a project registers and whether they're on an approved list
- Checking for environment variable usage vs. hardcoded credentials in MCP configs
- Any request like "is my MCP config secure?", "audit my MCP servers", or "check .mcp.json"
Expand Down Expand Up @@ -156,9 +156,21 @@ Review package-runner MCP entries for selectors that can resolve to different pa
```python
import re
EXACT_SEMVER = re.compile(r"^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$")
def split_package_spec(spec: str):
"""Split npm-style package selectors, including scoped packages."""
EXACT_PYTHON = re.compile(r"^===?\s*\d+(?:\.\d+)*(?:(?:a|b|rc)\d+)?(?:\.post\d+)?(?:\.dev\d+)?$")
PYTHON_SPEC = re.compile(r"([A-Za-z0-9][A-Za-z0-9._-]*(?:\[[^\]]*\])?)\s*((?:===?|~=|!=|<=?|>=?)\s*.+)")
PYTHON_RUNNERS = {"uvx", "uvx.exe", "uv", "uv.exe", "pipx", "pipx.exe"}


def launcher_name(server_config: dict) -> str:
return str(server_config.get("command", "")).replace("\\", "/").rsplit("/", 1)[-1].lower()


def split_package_spec(spec: str, python: bool = False):
"""Split npm-style selectors (including scoped packages) or Python requirements."""
spec = spec.strip()
requirement = PYTHON_SPEC.fullmatch(spec) if python else None
if requirement:
return requirement.group(1), requirement.group(2) # e.g. ("pkg", "==1.2.0")
if spec.startswith("@"):
slash = spec.find("/")
at = spec.rfind("@")
Expand All @@ -173,11 +185,25 @@ def split_package_spec(spec: str):

def package_specs_from_runner(server_config: dict):
"""Return selectors without running commands; None means manual review."""
command = str(server_config.get("command", "")).replace("\\", "/").rsplit("/", 1)[-1].lower()
command = launcher_name(server_config)
args = server_config.get("args", [])
if not isinstance(args, list) or not all(isinstance(arg, str) for arg in args):
return None
if command in {"npm", "npm.cmd"}:
package_flags = {"-p", "--package"}
ignored_flags = {"-y", "--yes", "--no", "--quiet"}
if command in PYTHON_RUNNERS:
if command in {"uv", "uv.exe"}:
if args[:2] != ["tool", "run"]:
return None
args = args[2:]
elif command in {"pipx", "pipx.exe"}:
if not args or args[0] != "run":
return None
args = args[1:]
# uvx -p means --python, so only the requirement flags name packages.
package_flags = {"--spec"} if command.startswith("pipx") else {"--from"}
ignored_flags = set()
elif command in {"npm", "npm.cmd"}:
if not args or args[0] not in {"exec", "x"}:
return None
args = args[1:]
Expand All @@ -192,16 +218,16 @@ def package_specs_from_runner(server_config: dict):
i = 0
while i < len(args):
arg = args[i]
if arg in {"-p", "--package"}:
if arg in package_flags:
i += 1
if i >= len(args) or not args[i] or args[i].startswith("-"):
return None
selectors.append(args[i])
elif arg.startswith("--package="):
elif arg.startswith("--") and arg.split("=", 1)[0] in package_flags:
if not arg.split("=", 1)[1]:
return None
selectors.append(arg.split("=", 1)[1])
elif arg in {"-y", "--yes", "--no", "--quiet"}:
elif arg in ignored_flags:
pass
elif arg == "--":
if selectors:
Expand All @@ -218,6 +244,9 @@ def package_specs_from_runner(server_config: dict):
def check_pinned_versions(server_config: dict) -> list[dict]:
"""Flag mutable selectors; report unsupported forms for manual review."""
specs = package_specs_from_runner(server_config)
python = launcher_name(server_config) in PYTHON_RUNNERS
if specs and python and any("://" in s or " @ " in s or s.startswith(("git+", ".", "/", "~", "file:")) for s in specs):
specs = None # Git, URL, and path sources: a tag or file can change; review by hand.
if specs is None:
return [{
"severity": "INFO",
Expand All @@ -227,8 +256,8 @@ def check_pinned_versions(server_config: dict) -> list[dict]:
}]
findings = []
for spec in specs:
package, version = split_package_spec(spec)
if version and EXACT_SEMVER.fullmatch(version):
package, version = split_package_spec(spec, python)
if version and (EXACT_SEMVER.fullmatch(version) or EXACT_PYTHON.fullmatch(version)):
continue
mutable_tag = version and re.fullmatch(r"[A-Za-z][A-Za-z0-9._-]*", version)
findings.append({
Expand All @@ -244,16 +273,20 @@ def check_pinned_versions(server_config: dict) -> list[dict]:
**Good — exact reviewed version:**
```json
{ "command": "npx", "args": ["-y", "my-mcp-server@2.1.0"] }
{ "command": "uvx", "args": ["my-mcp-server@2.1.0"] }
{ "command": "uvx", "args": ["--from", "my-mcp-server==2.1.0", "my-mcp-server"] }
```

**Review — mutable references:**
```json
{ "command": "npx", "args": ["-y", "my-mcp-server@latest"] }
{ "command": "npx", "args": ["-y", "my-mcp-server"] }
{ "command": "npx", "args": ["-y", "@scope/server@^2.1.0"] }
{ "command": "uvx", "args": ["my-mcp-server"] }
{ "command": "pipx", "args": ["run", "--spec", "my-mcp-server>=2.1", "my-mcp-server"] }
```

The extractor reviews every explicit `--package` / `-p` selector. Unknown launchers or flags require manual review rather than a clean result. An exact direct selector does not prove package integrity, benign behavior, or reproducibility of transitive dependencies without a lockfile.
The extractor reviews every explicit `--package` / `-p` selector for JavaScript runners, and every `--from` (`uvx`, `uv tool run`) or `--spec` (`pipx run`) requirement for Python runners. For `uvx`, `-p` selects the Python interpreter, not a package. Git, URL, and local path sources for Python runners (for example `git+https://...@v1.0.0`) go to manual review, because a tag or file can change behind an exact-looking reference. Unknown launchers or flags require manual review rather than a clean result. An exact direct selector does not prove package integrity, benign behavior, or reproducibility of transitive dependencies without a lockfile.

Do **not** invent a remediation pin by substituting today's registry version. Pin a version that was actually reviewed; if that evidence is unknown, record the uncertainty. `-y` / `--yes` suppresses an interactive prompt and may matter for CI ergonomics, but it is not a vulnerability by itself.

Expand Down
Loading