{"data":{"skill":{"slug":"asmayaseen-nextjs-devtools","name":"nextjs-devtools","icon":"📦","repo":"https://github.com/Asmayaseen/hackathon-2/tree/main/.claude/skills/nextjs-devtools","status":"approved","author":"Asmayaseen","authorVersion":null,"skillstoreRevision":null},"audit":{"id":"cae8b8ca-895c-4e85-ad36-67d537dd69cf","skill_id":"b3727549-2cea-4e1d-b4f4-bd852fa3f94d","version":8,"content_hash":"v2:1b5b6c4962b2ad5a7a34603cab2685bbbd1b61ef:c890548bba06f615f2900e2ec71355ba14cd5d7e6895615ababb39c8d7470261:94f65a384715934cd3e5bf2f172329959936ed9e9fed6d1b4f574fd2f03f2f3d:0a0b3a1187d6bea7ef88ccd93509fdfe","risk_level":"high","is_blocked":false,"safe_to_publish":false,"analysis_status":"ok","agent_auto_install_policy":"confirmation_required","manual_install_policy":"allowed","summary":"The skill has legitimate MCP client behavior, but it includes real external command and network surfaces. The main concerns are shell-based stdio command startup and repeated use of unpinned npx next-devtools-mcp@latest; no prompt injection or data-exfiltration intent was found.","remediation":[{"issue":"Stdio transport starts a shell command with shell=True.","severity":"high","suggestion":"Use an argument vector with shell=False, or restrict stdio commands to a small allowlist of trusted MCP server invocations."},{"issue":"Examples and startup script run next-devtools-mcp with @latest.","severity":"high","suggestion":"Pin a reviewed package version and update it through normal release review instead of resolving the latest version at runtime."},{"issue":"HTTP transport accepts arbitrary MCP URLs and headers.","severity":"low","suggestion":"Default to localhost, warn before external URLs, and avoid passing sensitive headers unless the endpoint is trusted."},{"issue":"Documentation encourages command execution without safety notes.","severity":"medium","suggestion":"Add clear guidance to run the skill only in trusted Next.js projects and to review MCP server commands before execution."}],"risk_factor_evidence":[{"factor":"external_commands","evidence":[{"file":"scripts/mcp-client.py","line_end":191,"line_start":191},{"file":"scripts/mcp-client.py","line_end":204,"line_start":204},{"file":"scripts/mcp-client.py","line_end":348,"line_start":348},{"file":"scripts/mcp-client.py","line_end":371,"line_start":371},{"file":"scripts/mcp-client.py","line_end":379,"line_start":377},{"file":"scripts/start-server.sh","line_end":1,"line_start":1},{"file":"SKILL.md","line_end":23,"line_start":15},{"file":"SKILL.md","line_end":29,"line_start":23},{"file":"SKILL.md","line_end":30,"line_start":29},{"file":"SKILL.md","line_end":31,"line_start":30},{"file":"SKILL.md","line_end":32,"line_start":31},{"file":"SKILL.md","line_end":33,"line_start":32},{"file":"SKILL.md","line_end":39,"line_start":33},{"file":"SKILL.md","line_end":50,"line_start":39},{"file":"SKILL.md","line_end":54,"line_start":50},{"file":"SKILL.md","line_end":64,"line_start":54},{"file":"SKILL.md","line_end":68,"line_start":64},{"file":"SKILL.md","line_end":72,"line_start":68},{"file":"SKILL.md","line_end":80,"line_start":72},{"file":"SKILL.md","line_end":84,"line_start":80},{"file":"SKILL.md","line_end":88,"line_start":84},{"file":"SKILL.md","line_end":90,"line_start":88},{"file":"SKILL.md","line_end":94,"line_start":90},{"file":"SKILL.md","line_end":100,"line_start":94},{"file":"SKILL.md","line_end":102,"line_start":100}]},{"factor":"network","evidence":[{"file":"scripts/mcp-client.py","line_end":146,"line_start":146},{"file":"scripts/mcp-client.py","line_end":271,"line_start":271},{"file":"scripts/mcp-client.py","line_end":314,"line_start":314},{"file":"scripts/mcp-client.py","line_end":323,"line_start":323},{"file":"scripts/mcp-client.py","line_end":328,"line_start":328},{"file":"scripts/mcp-client.py","line_end":333,"line_start":333},{"file":"scripts/mcp-client.py","line_end":33,"line_start":33},{"file":"scripts/mcp-client.py","line_end":10,"line_start":10},{"file":"scripts/mcp-client.py","line_end":16,"line_start":16},{"file":"scripts/mcp-client.py","line_end":20,"line_start":20},{"file":"scripts/mcp-client.py","line_end":23,"line_start":23},{"file":"scripts/start-server.sh","line_end":10,"line_start":10}]}],"critical_findings":[],"high_findings":[{"title":"Python subprocess.Popen","locations":[{"file":"scripts/mcp-client.py","line_end":204,"line_start":204}],"confidence":0.88,"description":"self._process = subprocess.Popen(","review_kind":"capability","source_category":"external_commands","source_severity":"high","confidence_reasoning":"subprocess.Popen starts self.command with shell=True, and that command is supplied through the --stdio option. This enables arbitrary local shell execution if an unsafe command is provided."},{"title":"Unpinned Remote MCP Package Execution","locations":[{"file":"SKILL.md","line_end":22,"line_start":20},{"file":"SKILL.md","line_end":43,"line_start":41},{"file":"SKILL.md","line_end":58,"line_start":56},{"file":"SKILL.md","line_end":71,"line_start":69},{"file":"SKILL.md","line_end":93,"line_start":91},{"file":"SKILL.md","line_end":100,"line_start":100},{"file":"scripts/start-server.sh","line_end":8,"line_start":8}],"confidence":0.88,"description":"The skill and startup script run npx next-devtools-mcp@latest, which executes whichever package version is current. This creates supply-chain risk because future package changes can alter behavior without a skill update.","review_kind":"security","source_category":"semantic","source_severity":"high","confidence_reasoning":"Multiple instructions and the startup script invoke the latest npm package directly. The exact version is not pinned, so the supply-chain risk is clear even if the package is legitimate today."}],"medium_findings":[{"title":"Unix shell invocation","locations":[{"file":"scripts/start-server.sh","line_end":1,"line_start":1}],"confidence":0.84,"description":"#!/bin/bash","review_kind":"capability","source_category":"external_commands","source_severity":"medium","confidence_reasoning":"This file is a shell script, and its body starts next-devtools-mcp through npx. Running it executes a local command and may retrieve npm package code."},{"title":"Ruby/shell backtick execution","locations":[{"file":"SKILL.md","line_end":23,"line_start":15}],"confidence":0.86,"description":"```bash","review_kind":"capability","source_category":"external_commands","source_severity":"medium","confidence_reasoning":"The fenced block gives commands that run the shell script and call the Python MCP client with an npx stdio server. This is real command execution guidance."},{"title":"Ruby/shell backtick execution","locations":[{"file":"SKILL.md","line_end":50,"line_start":39}],"confidence":0.86,"description":"```bash","review_kind":"capability","source_category":"external_commands","source_severity":"medium","confidence_reasoning":"The fenced block instructs users to run python3 scripts/mcp-client.py with an npx stdio command. This is intentional external command execution."},{"title":"Ruby/shell backtick execution","locations":[{"file":"SKILL.md","line_end":64,"line_start":54}],"confidence":0.86,"description":"```bash","review_kind":"capability","source_category":"external_commands","source_severity":"medium","confidence_reasoning":"The fenced block provides commands that run the Python MCP client and start an npx stdio server. Users or agents following it execute local commands."},{"title":"Ruby/shell backtick execution","locations":[{"file":"SKILL.md","line_end":72,"line_start":68}],"confidence":0.85,"description":"```bash","review_kind":"capability","source_category":"external_commands","source_severity":"medium","confidence_reasoning":"The fenced example invokes the Python MCP client with an npx stdio server. That guidance causes local external command execution."},{"title":"Ruby/shell backtick execution","locations":[{"file":"SKILL.md","line_end":84,"line_start":80}],"confidence":0.82,"description":"```bash","review_kind":"capability","source_category":"external_commands","source_severity":"medium","confidence_reasoning":"The fenced block tells users to run bash scripts/start-server.sh. That script starts the MCP server through a local shell command."},{"title":"Ruby/shell backtick execution","locations":[{"file":"SKILL.md","line_end":94,"line_start":90}],"confidence":0.84,"description":"```bash","review_kind":"capability","source_category":"external_commands","source_severity":"medium","confidence_reasoning":"The fenced on-demand example runs the Python MCP client with a stdio command placeholder. This is command execution guidance and should be treated as a real risk surface."},{"title":"Ruby/shell backtick execution","locations":[{"file":"SKILL.md","line_end":102,"line_start":100}],"confidence":0.74,"description":"| Server not starting | Check `npx next-devtools-mcp@latest` works manually |","review_kind":"capability","source_category":"external_commands","source_severity":"medium","confidence_reasoning":"The troubleshooting text tells users to check an npx command manually. It is less direct than a command block, but still encourages external command execution."}],"low_findings":[{"title":"HTTP client library","locations":[{"file":"scripts/mcp-client.py","line_end":146,"line_start":146}],"confidence":0.77,"description":"def request(self, method: str, params: Optional[dict] = None) -> dict:","review_kind":"capability","source_category":"network","source_severity":"low","confidence_reasoning":"HTTPTransport.request sends JSON-RPC requests to a user-supplied MCP HTTP endpoint. This is expected MCP behavior, but it is still real network capability."},{"title":"HTTP client library","locations":[{"file":"scripts/mcp-client.py","line_end":314,"line_start":314}],"confidence":0.62,"description":"result = self.transport.request(\"tools/list\")","review_kind":"capability","source_category":"network","source_severity":"low","confidence_reasoning":"This call uses the selected transport, which can be the HTTP transport. It is normal MCP tooling, but it may send a tools/list request over the network."},{"title":"HTTP client library","locations":[{"file":"scripts/mcp-client.py","line_end":323,"line_start":323}],"confidence":0.66,"description":"result = self.transport.request(\"tools/call\", params)","review_kind":"capability","source_category":"network","source_severity":"low","confidence_reasoning":"Tool call arguments are sent through the selected transport, which can be HTTP. This creates a low-risk data exposure surface if a remote endpoint is used."},{"title":"HTTP client library","locations":[{"file":"scripts/mcp-client.py","line_end":328,"line_start":328}],"confidence":0.6,"description":"result = self.transport.request(\"resources/list\")","review_kind":"capability","source_category":"network","source_severity":"low","confidence_reasoning":"Resource listing uses the selected transport, including HTTP when configured. The behavior is legitimate but confirms outbound MCP network support."},{"title":"HTTP client library","locations":[{"file":"scripts/mcp-client.py","line_end":333,"line_start":333}],"confidence":0.6,"description":"result = self.transport.request(\"prompts/list\")","review_kind":"capability","source_category":"network","source_severity":"low","confidence_reasoning":"Prompt listing uses the selected transport, including HTTP when configured. No exfiltration intent is shown, but network use is real."},{"title":"Python HTTP libraries","locations":[{"file":"scripts/mcp-client.py","line_end":33,"line_start":33}],"confidence":0.78,"description":"from urllib.request import Request, urlopen","review_kind":"capability","source_category":"network","source_severity":"low","confidence_reasoning":"The urllib request imports are used by HTTPTransport for outbound MCP requests. This confirms network capability, although endpoints are user supplied."}],"dangerous_patterns":[],"files_scanned":3,"total_lines":602,"audit_model":"codex","audited_at":"2026-07-07T22:03:57.553+00:00","created_at":"2026-07-08T00:39:09.668853+00:00","static_findings":[{"id":"external_commands:scripts/mcp-client.py:191:python-subprocess-popen","file":"scripts/mcp-client.py","pattern":"Python subprocess.Popen","snippet":"self._process: Optional[subprocess.Popen] = None","category":"external_commands","line_end":191,"severity":"high","line_start":191},{"id":"external_commands:scripts/mcp-client.py:204:python-subprocess-popen","file":"scripts/mcp-client.py","pattern":"Python subprocess.Popen","snippet":"self._process = subprocess.Popen(","category":"external_commands","line_end":204,"severity":"high","line_start":204},{"id":"external_commands:scripts/mcp-client.py:348:ruby-shell-backtick-execution","file":"scripts/mcp-client.py","pattern":"Ruby/shell backtick execution","snippet":"lines.append(f\"## `{name}`\\n\")","category":"external_commands","line_end":348,"severity":"medium","line_start":348},{"id":"external_commands:scripts/mcp-client.py:371:ruby-shell-backtick-execution","file":"scripts/mcp-client.py","pattern":"Ruby/shell backtick execution","snippet":"lines.append(f\"- **`{prop_name}`** (`{prop_type}`){req_marker}: {prop_desc}\")","category":"external_commands","line_end":371,"severity":"medium","line_start":371},{"id":"external_commands:scripts/mcp-client.py:377:ruby-shell-backtick-execution","file":"scripts/mcp-client.py","pattern":"Ruby/shell backtick execution","snippet":"lines.append(\"```json\")","category":"external_commands","line_end":379,"severity":"medium","line_start":377},{"id":"network:scripts/mcp-client.py:146:http-client-library","file":"scripts/mcp-client.py","pattern":"HTTP client library","snippet":"def request(self, method: str, params: Optional[dict] = None) -> dict:","category":"network","line_end":146,"severity":"low","line_start":146},{"id":"network:scripts/mcp-client.py:271:http-client-library","file":"scripts/mcp-client.py","pattern":"HTTP client library","snippet":"def request(self, method: str, params: Optional[dict] = None) -> dict:","category":"network","line_end":271,"severity":"low","line_start":271},{"id":"network:scripts/mcp-client.py:314:http-client-library","file":"scripts/mcp-client.py","pattern":"HTTP client library","snippet":"result = self.transport.request(\"tools/list\")","category":"network","line_end":314,"severity":"low","line_start":314},{"id":"network:scripts/mcp-client.py:323:http-client-library","file":"scripts/mcp-client.py","pattern":"HTTP client library","snippet":"result = self.transport.request(\"tools/call\", params)","category":"network","line_end":323,"severity":"low","line_start":323},{"id":"network:scripts/mcp-client.py:328:http-client-library","file":"scripts/mcp-client.py","pattern":"HTTP client library","snippet":"result = self.transport.request(\"resources/list\")","category":"network","line_end":328,"severity":"low","line_start":328},{"id":"network:scripts/mcp-client.py:333:http-client-library","file":"scripts/mcp-client.py","pattern":"HTTP client library","snippet":"result = self.transport.request(\"prompts/list\")","category":"network","line_end":333,"severity":"low","line_start":333},{"id":"network:scripts/mcp-client.py:33:python-http-libraries","file":"scripts/mcp-client.py","pattern":"Python HTTP libraries","snippet":"from urllib.request import Request, urlopen","category":"network","line_end":33,"severity":"low","line_start":33},{"id":"network:scripts/mcp-client.py:10:hardcoded-url","file":"scripts/mcp-client.py","pattern":"Hardcoded URL","snippet":"python mcp-client.py list --url http://localhost:8080","category":"network","line_end":10,"severity":"low","line_start":10},{"id":"network:scripts/mcp-client.py:16:hardcoded-url","file":"scripts/mcp-client.py","pattern":"Hardcoded URL","snippet":"python mcp-client.py call --url http://localhost:8080 --tool create_issue \\","category":"network","line_end":16,"severity":"low","line_start":16},{"id":"network:scripts/mcp-client.py:20:hardcoded-url","file":"scripts/mcp-client.py","pattern":"Hardcoded URL","snippet":"python mcp-client.py emit --url http://localhost:8080","category":"network","line_end":20,"severity":"low","line_start":20},{"id":"network:scripts/mcp-client.py:23:hardcoded-url","file":"scripts/mcp-client.py","pattern":"Hardcoded URL","snippet":"python mcp-client.py emit --url http://localhost:8080 --format json","category":"network","line_end":23,"severity":"low","line_start":23},{"id":"blocker:scripts/mcp-client.py:52:system-reconnaissance","file":"scripts/mcp-client.py","pattern":"System reconnaissance","snippet":"self._request_id = 0","category":"blocker","line_end":52,"severity":"low","line_start":52},{"id":"blocker:scripts/mcp-client.py:57:system-reconnaissance","file":"scripts/mcp-client.py","pattern":"System reconnaissance","snippet":"self._request_id += 1","category":"blocker","line_end":57,"severity":"low","line_start":57},{"id":"blocker:scripts/mcp-client.py:58:system-reconnaissance","file":"scripts/mcp-client.py","pattern":"System reconnaissance","snippet":"return self._request_id","category":"blocker","line_end":60,"severity":"low","line_start":58},{"id":"blocker:scripts/mcp-client.py:88:system-reconnaissance","file":"scripts/mcp-client.py","pattern":"System reconnaissance","snippet":"self._session_id = resp.headers.get('Mcp-Session-Id')","category":"blocker","line_end":88,"severity":"low","line_start":88},{"id":"blocker:scripts/mcp-client.py:137:system-reconnaissance","file":"scripts/mcp-client.py","pattern":"System reconnaissance","snippet":"headers[\"Mcp-Session-Id\"] = self._session_id","category":"blocker","line_end":139,"severity":"low","line_start":137},{"id":"blocker:scripts/mcp-client.py:165:system-reconnaissance","file":"scripts/mcp-client.py","pattern":"System reconnaissance","snippet":"headers[\"Mcp-Session-Id\"] = self._session_id","category":"blocker","line_end":167,"severity":"low","line_start":165},{"id":"blocker:scripts/mcp-client.py:190:system-reconnaissance","file":"scripts/mcp-client.py","pattern":"System reconnaissance","snippet":"self._request_id = 0","category":"blocker","line_end":190,"severity":"low","line_start":190},{"id":"blocker:scripts/mcp-client.py:196:system-reconnaissance","file":"scripts/mcp-client.py","pattern":"System reconnaissance","snippet":"self._request_id += 1","category":"blocker","line_end":196,"severity":"low","line_start":196},{"id":"blocker:scripts/mcp-client.py:197:system-reconnaissance","file":"scripts/mcp-client.py","pattern":"System reconnaissance","snippet":"return self._request_id","category":"blocker","line_end":199,"severity":"low","line_start":197},{"id":"blocker:scripts/mcp-client.py:275:system-reconnaissance","file":"scripts/mcp-client.py","pattern":"System reconnaissance","snippet":"req_id = self._next_id()","category":"blocker","line_end":275,"severity":"low","line_start":275},{"id":"blocker:scripts/mcp-client.py:286:system-reconnaissance","file":"scripts/mcp-client.py","pattern":"System reconnaissance","snippet":"# Wait for response with matching id","category":"blocker","line_end":287,"severity":"low","line_start":286},{"id":"blocker:scripts/mcp-client.py:480:system-reconnaissance","file":"scripts/mcp-client.py","pattern":"System reconnaissance","snippet":"print(f\"Invalid JSON: {e}\", file=sys.stderr)","category":"blocker","line_end":480,"severity":"low","line_start":480},{"id":"external_commands:scripts/start-server.sh:1:unix-shell-invocation","file":"scripts/start-server.sh","pattern":"Unix shell invocation","snippet":"#!/bin/bash","category":"external_commands","line_end":1,"severity":"medium","line_start":1},{"id":"network:scripts/start-server.sh:10:hardcoded-url","file":"scripts/start-server.sh","pattern":"Hardcoded URL","snippet":"echo \"Server started. Use mcp-client.py with -u http://localhost:$PORT\"","category":"network","line_end":10,"severity":"low","line_start":10},{"id":"external_commands:SKILL.md:15:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```bash","category":"external_commands","line_end":23,"severity":"medium","line_start":15},{"id":"external_commands:SKILL.md:23:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":29,"severity":"medium","line_start":23},{"id":"external_commands:SKILL.md:29:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| `list-routes` | Get all app routes |","category":"external_commands","line_end":30,"severity":"medium","line_start":29},{"id":"external_commands:SKILL.md:30:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| `get-route-info` | Details for specific route |","category":"external_commands","line_end":31,"severity":"medium","line_start":30},{"id":"external_commands:SKILL.md:31:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| `list-components` | React components in app |","category":"external_commands","line_end":32,"severity":"medium","line_start":31},{"id":"external_commands:SKILL.md:32:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| `get-build-info` | Build configuration |","category":"external_commands","line_end":33,"severity":"medium","line_start":32},{"id":"external_commands:SKILL.md:33:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| `get-config` | next.config.js settings |","category":"external_commands","line_end":39,"severity":"medium","line_start":33},{"id":"external_commands:SKILL.md:39:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```bash","category":"external_commands","line_end":50,"severity":"medium","line_start":39},{"id":"external_commands:SKILL.md:50:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":54,"severity":"medium","line_start":50},{"id":"external_commands:SKILL.md:54:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```bash","category":"external_commands","line_end":64,"severity":"medium","line_start":54},{"id":"external_commands:SKILL.md:64:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":68,"severity":"medium","line_start":64},{"id":"external_commands:SKILL.md:68:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```bash","category":"external_commands","line_end":72,"severity":"medium","line_start":68},{"id":"external_commands:SKILL.md:72:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":80,"severity":"medium","line_start":72},{"id":"external_commands:SKILL.md:80:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```bash","category":"external_commands","line_end":84,"severity":"medium","line_start":80},{"id":"external_commands:SKILL.md:84:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":88,"severity":"medium","line_start":84},{"id":"external_commands:SKILL.md:88:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"For single calls, use `-s` flag which spawns server per-call:","category":"external_commands","line_end":90,"severity":"medium","line_start":88},{"id":"external_commands:SKILL.md:90:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```bash","category":"external_commands","line_end":94,"severity":"medium","line_start":90},{"id":"external_commands:SKILL.md:94:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"```","category":"external_commands","line_end":100,"severity":"medium","line_start":94},{"id":"external_commands:SKILL.md:100:ruby-shell-backtick-execution","file":"SKILL.md","pattern":"Ruby/shell backtick execution","snippet":"| Server not starting | Check `npx next-devtools-mcp@latest` works manually |","category":"external_commands","line_end":102,"severity":"medium","line_start":100}],"finding_verdicts":[{"id":"external_commands:scripts/mcp-client.py:191:python-subprocess-popen","reason":"This line is only a type annotation for a stored process handle. It does not start a process or accept command input.","verdict":"false_positive","confidence":0.93},{"id":"external_commands:scripts/mcp-client.py:204:python-subprocess-popen","reason":"subprocess.Popen starts self.command with shell=True, and that command is supplied through the --stdio option. This enables arbitrary local shell execution if an unsafe command is provided.","verdict":"confirmed","severity":"high","confidence":0.88},{"id":"external_commands:scripts/mcp-client.py:348:ruby-shell-backtick-execution","reason":"The backticks are Markdown formatting around a tool name in generated documentation. They are not evaluated by a shell.","verdict":"false_positive","confidence":0.98},{"id":"external_commands:scripts/mcp-client.py:371:ruby-shell-backtick-execution","reason":"The backticks format parameter names and types in Markdown output. No command execution path is present on this line.","verdict":"false_positive","confidence":0.98},{"id":"external_commands:scripts/mcp-client.py:377:ruby-shell-backtick-execution","reason":"This writes a Markdown JSON code fence string. It is documentation output, not Ruby or shell execution.","verdict":"false_positive","confidence":0.98},{"id":"network:scripts/mcp-client.py:146:http-client-library","reason":"HTTPTransport.request sends JSON-RPC requests to a user-supplied MCP HTTP endpoint. This is expected MCP behavior, but it is still real network capability.","verdict":"confirmed","severity":"low","confidence":0.77},{"id":"network:scripts/mcp-client.py:271:http-client-library","reason":"This request method belongs to the stdio transport and communicates through a local child process pipe. It does not use an HTTP client.","verdict":"false_positive","confidence":0.91},{"id":"network:scripts/mcp-client.py:314:http-client-library","reason":"This call uses the selected transport, which can be the HTTP transport. It is normal MCP tooling, but it may send a tools/list request over the network.","verdict":"confirmed","severity":"low","confidence":0.62},{"id":"network:scripts/mcp-client.py:323:http-client-library","reason":"Tool call arguments are sent through the selected transport, which can be HTTP. This creates a low-risk data exposure surface if a remote endpoint is used.","verdict":"confirmed","severity":"low","confidence":0.66},{"id":"network:scripts/mcp-client.py:328:http-client-library","reason":"Resource listing uses the selected transport, including HTTP when configured. The behavior is legitimate but confirms outbound MCP network support.","verdict":"confirmed","severity":"low","confidence":0.6},{"id":"network:scripts/mcp-client.py:333:http-client-library","reason":"Prompt listing uses the selected transport, including HTTP when configured. No exfiltration intent is shown, but network use is real.","verdict":"confirmed","severity":"low","confidence":0.6},{"id":"network:scripts/mcp-client.py:33:python-http-libraries","reason":"The urllib request imports are used by HTTPTransport for outbound MCP requests. This confirms network capability, although endpoints are user supplied.","verdict":"confirmed","severity":"low","confidence":0.78},{"id":"network:scripts/mcp-client.py:10:hardcoded-url","reason":"The URL appears only in a usage example and points to localhost. It does not hardcode an external destination in executable logic.","verdict":"false_positive","confidence":0.96},{"id":"network:scripts/mcp-client.py:16:hardcoded-url","reason":"The URL is a localhost usage example in the module docstring. It is not an automatic network request.","verdict":"false_positive","confidence":0.96},{"id":"network:scripts/mcp-client.py:20:hardcoded-url","reason":"The URL is documentation for emitting schemas from a local MCP server. It does not force traffic to an external host.","verdict":"false_positive","confidence":0.96},{"id":"network:scripts/mcp-client.py:23:hardcoded-url","reason":"The URL is a localhost example in documentation text. It is not embedded as an outbound endpoint in runtime code.","verdict":"false_positive","confidence":0.96},{"id":"blocker:scripts/mcp-client.py:52:system-reconnaissance","reason":"This stores a JSON-RPC request counter. It does not collect host, user, file system, or network reconnaissance data.","verdict":"false_positive","confidence":0.95},{"id":"blocker:scripts/mcp-client.py:57:system-reconnaissance","reason":"This increments a JSON-RPC request counter. It is protocol bookkeeping, not system reconnaissance.","verdict":"false_positive","confidence":0.95},{"id":"blocker:scripts/mcp-client.py:58:system-reconnaissance","reason":"This returns the next JSON-RPC request id. No system details are gathered or transmitted.","verdict":"false_positive","confidence":0.95},{"id":"blocker:scripts/mcp-client.py:88:system-reconnaissance","reason":"This reads an MCP session id from response headers for protocol continuity. It is not probing local system information.","verdict":"false_positive","confidence":0.94},{"id":"blocker:scripts/mcp-client.py:137:system-reconnaissance","reason":"This adds the MCP session id to a follow-up request. It is session handling, not reconnaissance.","verdict":"false_positive","confidence":0.94},{"id":"blocker:scripts/mcp-client.py:165:system-reconnaissance","reason":"This reuses the MCP session id header for JSON-RPC requests. It does not inspect system state.","verdict":"false_positive","confidence":0.94},{"id":"blocker:scripts/mcp-client.py:190:system-reconnaissance","reason":"This initializes a stdio JSON-RPC request counter. It is not a discovery or reconnaissance mechanism.","verdict":"false_positive","confidence":0.95},{"id":"blocker:scripts/mcp-client.py:196:system-reconnaissance","reason":"This increments a local request id counter for stdio messages. It does not collect system information.","verdict":"false_positive","confidence":0.95},{"id":"blocker:scripts/mcp-client.py:197:system-reconnaissance","reason":"This returns the current JSON-RPC request id. There is no host inspection or data collection on this line.","verdict":"false_positive","confidence":0.95},{"id":"blocker:scripts/mcp-client.py:275:system-reconnaissance","reason":"This obtains a request id before sending an MCP message. It is protocol bookkeeping, not reconnaissance.","verdict":"false_positive","confidence":0.95},{"id":"blocker:scripts/mcp-client.py:286:system-reconnaissance","reason":"The comment describes waiting for a matching JSON-RPC response id. It does not indicate system reconnaissance.","verdict":"false_positive","confidence":0.95},{"id":"blocker:scripts/mcp-client.py:480:system-reconnaissance","reason":"This prints a JSON parsing error to stderr. It does not enumerate or transmit system details.","verdict":"false_positive","confidence":0.94},{"id":"external_commands:scripts/start-server.sh:1:unix-shell-invocation","reason":"This file is a shell script, and its body starts next-devtools-mcp through npx. Running it executes a local command and may retrieve npm package code.","verdict":"confirmed","severity":"medium","confidence":0.84},{"id":"network:scripts/start-server.sh:10:hardcoded-url","reason":"This line only prints a localhost URL for the user. It does not initiate a network request or hardcode an external endpoint.","verdict":"false_positive","confidence":0.95},{"id":"external_commands:SKILL.md:15:ruby-shell-backtick-execution","reason":"The fenced block gives commands that run the shell script and call the Python MCP client with an npx stdio server. This is real command execution guidance.","verdict":"confirmed","severity":"medium","confidence":0.86},{"id":"external_commands:SKILL.md:23:ruby-shell-backtick-execution","reason":"This is a Markdown fence boundary and nearby table formatting. It is not itself a command or executable instruction.","verdict":"false_positive","confidence":0.93},{"id":"external_commands:SKILL.md:29:ruby-shell-backtick-execution","reason":"The backticks format the list-routes MCP tool name in a table. They are not shell backticks.","verdict":"false_positive","confidence":0.97},{"id":"external_commands:SKILL.md:30:ruby-shell-backtick-execution","reason":"The backticks format the get-route-info MCP tool name in documentation. No command execution is described on this line.","verdict":"false_positive","confidence":0.97},{"id":"external_commands:SKILL.md:31:ruby-shell-backtick-execution","reason":"The backticks format the list-components MCP tool name in a table. This is Markdown text, not shell execution.","verdict":"false_positive","confidence":0.97},{"id":"external_commands:SKILL.md:32:ruby-shell-backtick-execution","reason":"The backticks format the get-build-info MCP tool name. It is documentation, not executable shell syntax.","verdict":"false_positive","confidence":0.97},{"id":"external_commands:SKILL.md:33:ruby-shell-backtick-execution","reason":"The backticks format the get-config MCP tool name in a table. This is not Ruby or shell command execution.","verdict":"false_positive","confidence":0.97},{"id":"external_commands:SKILL.md:39:ruby-shell-backtick-execution","reason":"The fenced block instructs users to run python3 scripts/mcp-client.py with an npx stdio command. This is intentional external command execution.","verdict":"confirmed","severity":"medium","confidence":0.86},{"id":"external_commands:SKILL.md:50:ruby-shell-backtick-execution","reason":"This is a Markdown code fence boundary after an example block. It does not create a shell execution path by itself.","verdict":"false_positive","confidence":0.93},{"id":"external_commands:SKILL.md:54:ruby-shell-backtick-execution","reason":"The fenced block provides commands that run the Python MCP client and start an npx stdio server. Users or agents following it execute local commands.","verdict":"confirmed","severity":"medium","confidence":0.86},{"id":"external_commands:SKILL.md:64:ruby-shell-backtick-execution","reason":"This is a Markdown fence boundary after command examples. It is not an executable instruction.","verdict":"false_positive","confidence":0.93},{"id":"external_commands:SKILL.md:68:ruby-shell-backtick-execution","reason":"The fenced example invokes the Python MCP client with an npx stdio server. That guidance causes local external command execution.","verdict":"confirmed","severity":"medium","confidence":0.85},{"id":"external_commands:SKILL.md:72:ruby-shell-backtick-execution","reason":"This is a Markdown code fence boundary before explanatory text. It is not a command execution construct.","verdict":"false_positive","confidence":0.93},{"id":"external_commands:SKILL.md:80:ruby-shell-backtick-execution","reason":"The fenced block tells users to run bash scripts/start-server.sh. That script starts the MCP server through a local shell command.","verdict":"confirmed","severity":"medium","confidence":0.82},{"id":"external_commands:SKILL.md:84:ruby-shell-backtick-execution","reason":"This is a Markdown fence boundary and surrounding prose. It is not a shell execution primitive.","verdict":"false_positive","confidence":0.93},{"id":"external_commands:SKILL.md:88:ruby-shell-backtick-execution","reason":"The backticks format the -s flag name in prose. The line itself does not execute or embed a command.","verdict":"false_positive","confidence":0.96},{"id":"external_commands:SKILL.md:90:ruby-shell-backtick-execution","reason":"The fenced on-demand example runs the Python MCP client with a stdio command placeholder. This is command execution guidance and should be treated as a real risk surface.","verdict":"confirmed","severity":"medium","confidence":0.84},{"id":"external_commands:SKILL.md:94:ruby-shell-backtick-execution","reason":"This is a Markdown code fence boundary before a troubleshooting table. It is not an executable command.","verdict":"false_positive","confidence":0.93},{"id":"external_commands:SKILL.md:100:ruby-shell-backtick-execution","reason":"The troubleshooting text tells users to check an npx command manually. It is less direct than a command block, but still encourages external command execution.","verdict":"confirmed","severity":"medium","confidence":0.74}],"semantic_findings":[{"title":"Unpinned Remote MCP Package Execution","severity":"high","locations":[{"file":"SKILL.md","line_end":22,"line_start":20},{"file":"SKILL.md","line_end":43,"line_start":41},{"file":"SKILL.md","line_end":58,"line_start":56},{"file":"SKILL.md","line_end":71,"line_start":69},{"file":"SKILL.md","line_end":93,"line_start":91},{"file":"SKILL.md","line_end":100,"line_start":100},{"file":"scripts/start-server.sh","line_end":8,"line_start":8}],"confidence":0.88,"description":"The skill and startup script run npx next-devtools-mcp@latest, which executes whichever package version is current. This creates supply-chain risk because future package changes can alter behavior without a skill update.","confidence_reasoning":"Multiple instructions and the startup script invoke the latest npm package directly. The exact version is not pinned, so the supply-chain risk is clear even if the package is legitimate today."}],"subject_marketplace_commit_sha":null,"subject_content_hash":null,"subject_tree_hash":null,"subject_plugin_path":null,"audit_payload_hash":null,"confirmed_risk_level":null,"scanner_version":null,"policy_version":null,"subject":{"marketplaceCommitSha":null,"contentHash":null,"treeHash":null,"pluginPath":null,"auditPayloadHash":null},"scannerVersion":null,"policyVersion":null},"auditTranslation":null,"localization":{"requestedLocale":"en","contentLocale":"en","availableLocales":["en"],"fallbackToEnglish":false},"attestation":{"availability":"not_attestable","url":null,"status":null,"reason":"confirmed_risk_level does not match the canonical trust resolver"},"trust":{"publicState":"public","auditState":"complete","auditCurrentness":null,"confirmedRiskLevel":"high","confirmedFindingCount":1,"capabilityReviewCount":15,"needsReviewCount":0,"falsePositiveCount":0,"agentAutoInstallPolicy":"confirmation_required","manualInstallPolicy":"allowed","artifactSignatureState":"available","attestationState":"not_attestable","verificationState":"not_verified"},"isLatest":false}}