← All MCP servers
MCP server

Devloop

mcp:vincentvella/devloop

Browser + dev-server logs on one correlated timeline, for Claude Code and AI agents.

Verdict
Suspicious

Risky behavior the analysis could not rule out.

Analyzed Oct 26, 2026, 13:21 UTC at 432c8e8
2
findings
high
highest severity
2
threat classes
247
files scanned
1,150/1,150
checks satisfied
0
package advisories

Why this verdict

mcp-server . Suspicious
  • suspicious: finding mcp-server:.:src/simulator.ts:91:SUPPLY
  • suspicious: unverified finding mcp-server:.:src/daemonClient.ts:98:PERSIST
skill .claude/skills/release No issues found
  • benign: 37 checks satisfied, no findings for skill:.claude/skills/release
skill skills/devloop No issues found
  • benign: 22 checks satisfied, no findings for skill:skills/devloop

Security findings 2

Persistence

highUnverifiedlow confidence

ensureDaemon spawns a detached daemon process that outlives the session, inheriting the full process environment, and serves an MCP tool layer (browser evaluate, dev server start) over HTTP; this is documented shared-mode behavior with an idle exit.

spawn(process.execPath, [self, "daemon"], spawnOpts).unref();
vector:code

Supply chain

mediumContextual risklow confidence

The serve-sim launcher fetches and runs an unpinned package via `npx -y` (and `bunx`) with no version pin, which is undeclared remote code execution from the registry.

{ cmd: "npx", args: ["-y", "serve-sim", "--port", String(SERVE_SIM_PORT)] }
vector:code
Counter-argument considered

The npx -y fallback fetches and runs serve-sim from the registry with no version pin. The comment discloses the launcher but not the lack of a pin, so the supply-chain weakness stands, at low severity.

Refuted findings 10

Candidates the review stage examined and rejected, kept for transparency.

Code execution

criticalRefutedlow confidence

DevServer.start interpolates a caller-supplied command string into a shell wrapper and runs it with shell:true and the full inherited environment; this is the declared dev-server capability, but the command source is the MCP caller.

( ${cmd} ) & CMD=$!; 
Why it was refuted

Running a caller-supplied command line in a shell is the declared core dev-server capability, and the code comment states it.

Code execution

criticalRefutedlow confidence

The dev_start tool passes an agent-supplied `cmd` and `cwd` argument to devServer.start, so a caller can launch an arbitrary command in an arbitrary directory; this is the declared dev-server-runner purpose and the destination is not shown here.

const cmd = (args.cmd as string | undefined) ?? proj?.cmd ?? detectDevCommand(cwd);
Why it was refuted

dev_start is the declared dev-server tool. Passing cmd and cwd to a shell-based dev server is its intended purpose, as the devServer code states.

Supply chain

criticalRefutedlow confidence

The release CI workflow downloads the latest mcp-publisher binary from the upstream registry's mutable 'latest' release, extracts it, and runs it with an OIDC token (publisher is unpinned and unverified by checksum).

curl -fsSL "$url" | tar -xz mcp-publisher
Why it was refuted

The download is the official MCP Registry publisher, used in the declared publish workflow. It runs in CI and is piped to tar, not to a shell, so it is not a concealed or undeclared behavior.

Code execution

highRefutedlow confidence

The daemon's HTTP MCP endpoint (browser evaluate, dev_start shell commands) is loopback by default but DEVLOOP_HTTP_HOST can bind it to all interfaces; no authentication is visible in these units.

host: env.DEVLOOP_HTTP_HOST || "127.0.0.1",
Why it was refuted

The bind address is loopback by default. Exposing it requires the operator to set DEVLOOP_HTTP_HOST explicitly, and the code comment says so.

Data exfiltration

highRefutedlow confidence

The HTTP MCP transport has no authentication and answers non-/mcp paths with a wildcard CORS header, so any local process or webpage able to reach the loopback port could drive the shared browser tools (evaluate, network/HAR, cookie-bearing sessions).

res.setHeader("Access-Control-Allow-Origin", "*"); // so cross-origin probes get the response
Why it was refuted

The wildcard CORS header is set only on the non-/mcp 404 and 400 error responses, not on the /mcp tool endpoint. The endpoint binds to loopback by default, so the claimed web-page-driven tool access has no supporting chain.

Code execution

highRefutedlow confidence

At startup the server spawns a shell command taken from the DEVLOOP_DEV_CMD environment variable; this is the declared dev-server feature, and the command comes from operator-controlled configuration, not from untrusted content.

devServer.start(process.env.DEVLOOP_DEV_CMD, process.env.DEVLOOP_DEV_CWD ?? process.cwd());
Why it was refuted

DEVLOOP_DEV_CMD is a documented, operator-set boot auto-start option for the declared dev-server feature. It is not attacker-controlled content.

Supply chain

highRefutedlow confidence

The release workflow downloads the latest mcp-publisher binary from a mutable upstream 'latest' release without pinning or checksum verification and then runs it with an OIDC publishing token; this is not named in the skill's declared description.

curl -fsSL "$url" | tar -xz mcp-publisher
Why it was refuted

Fetching the official registry's publisher is an integral part of the publish workflow the skill triggers, and the workflow comment documents it. The step runs in CI and is piped to tar, not to a shell.

Credential access

highRefutedlow confidence

The notes suggest that mcporter auto-import the user's existing Claude/Cursor/Codex MCP configs (which can hold tokens and server credentials) and persist config to ~/.mcporter, which goes beyond the declared purpose of driving Devloop.

rely on its auto-import from an
Why it was refuted

The note is an optional convenience: mcporter can reuse existing MCP config so the --http-url flags can be dropped. It does not instruct the agent to read, send or exfiltrate credentials.

Supply chain

highRefutedmedium confidence

The setup instructs the agent to run unpinned npm packages (npx -y devloop-mcp, npx mcporter) that fetch and execute the latest remote code, including a long-running background daemon, without version pinning.

npx -y devloop-mcp daemon &
Why it was refuted

The npx command runs the skill's own declared devloop-mcp package from the npm registry. It sits in fenced setup docs as a fallback for when the package is not installed, which is the accepted vendor-install carve-out.

Supply chain

mediumRefutedlow confidence

The devDependency @types/bun is pinned to the moving tag `latest` instead of a fixed version; it is a type-only dev dependency not shipped in the published package (files: dist), so impact is limited to development and build.

"@types/bun": "latest"
Why it was refuted

The unpinned entry is a type-only devDependency from the npm registry, not runtime code and not an agent instruction. It does not reach the agent or the shipped package.

Coverage gaps 6

Parts of the artifact the static analysis could not fully examine.

context:unanalyzable_binary binary content is only byte-scanned
assets/icon.icns
context:unanalyzable_binary binary content is only byte-scanned
assets/icon.ico
context:unanalyzable_binary binary content is only byte-scanned
web/public/demo.mp4
context:unanalyzable_binary binary content is only byte-scanned
web/public/demo.webm
dynamic_metadata line 134: tools list returned by ListToolsRequestSchema handler is computed
src/daemonClient.ts
no_tools_extracted MCP server target with no statically extractable tools/prompts/resources
package.json