registry  /  mcp-runrunit  /  1.8.1

mcp-runrunit@1.8.1

MCP server for Runrun.it API - Tasks, Comments, Projects

AI Security Review

scanned 3h ago · by lpm-firewall-ai

LPM treats this as warn-only first-party agent extension lifecycle risk. No confirmed malicious attack surface was found. The package does expose explicit MCP tools that mutate Cursor skills/agents and share local Cursor content through GitHub or Bitbucket PRs, which is agent-extension lifecycle risk rather than install-time compromise.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
User runs the MCP server and invokes Cursor install/share tools.
Impact
May write bundled agent/skill files into Cursor configuration paths or publish selected local Cursor files to configured repositories using host credentials.
Mechanism
explicit Cursor extension copy and repository PR creation
Rationale
Static inspection does not support the scanner's malicious exfiltration label; the risky primitives are user-invoked MCP capabilities aligned with the package purpose. Because it can mutate AI-agent configuration surfaces, a warn-level lifecycle/capability risk is appropriate, not a publish block.
Evidence
package.jsondist/index.jsdist/server.jsdist/adapters/driven/api.jsdist/adapters/driven/github.jsdist/adapters/driven/bitbucket.jsdist/adapters/driven/discord.jsdist/application/install-cursor-skills.jsdist/application/install-cursor-agents.jsdist/application/share-cursor-github.jsdist/application/share-cursor-paths.jsdist/application/git-repo-detect.js~/.cursor/skills<project_root>/.cursor/skills~/.cursor/agents<project_root>/.cursor/agentsmcp-debug.logcursor-skills/*cursor-agents/*
Network endpoints5
runrun.it/api/v1.0discord.com/api/v10api.bitbucket.org/2.0api.github.comuploads.github.com

Decision evidence

public snapshot
AI called this Suspicious at 86.0% confidence as Dangerous Capability with medium false-positive risk.
Evidence for warning
  • MCP tools copy bundled skills/agents into ~/.cursor or project .cursor paths on explicit tool calls: dist/application/install-cursor-skills.js, dist/application/install-cursor-agents.js.
  • Share tools can read cursor-skills/cursor-agents from a project and open GitHub/Bitbucket PRs using host env credentials: dist/application/share-cursor-github.js, dist/adapters/driven/github.js, dist/adapters/driven/bitbucket.js.
  • Runtime uses child_process execFileSync only for git remote/default-branch detection during share flow: dist/application/git-repo-detect.js.
Evidence against
  • package.json has no preinstall/install/postinstall hook; prepare only runs husky and build for development/publish flows.
  • Network use is package-aligned: Runrun.it API, Discord API, GitHub/Bitbucket PR APIs, optional Sentry with sanitization.
  • Runrun.it credentials are sent only as headers to https://runrun.it/api/v1.0 in dist/adapters/driven/api.js.
  • Cursor writes are explicit MCP tools, not import-time or install-time mutation, and destination checks require .cursor/skills or .cursor/agents.
  • No confirmed credential harvesting, arbitrary remote payload execution, destructive persistence, or stealth exfiltration found.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsEvalFilesystemNetworkShell
Supply chain
HighEntropyStringsUrlStrings
Manifest
NoLicense
scanned 43 file(s), 992 KB of source, external domains: 127.0.0.1, api.bitbucket.org, api.github.com, bitbucket.org, discord.com, docs.github.com, fetch.spec.whatwg.org, figma.com, gist.github.com, github.com, gitlab.com, json-schema.org, link-da-tarefa.com, mathiasbynens.be, raw.githubusercontent.com, runrun.it, spec.openapis.org, stackoverflow.com, tools.ietf.org, uploads.github.com, www.w3.org

Source & flagged code

6 flagged · loading source
dist/index.jsView file
1225// validation function arguments L1226: data: new codegen_1.Name("data"), L1227: // data passed to validation function ... L2252: id = normalizeId(id); L2253: return resolver.resolve(baseId, id); L2254: } ... L3112: for (i = 0; i < input.length; i++) { L3113: code = input[i].charCodeAt(0); L3114: if (code === 48) { ... L12164: var StdioServerTransport = class { L12165: constructor(_stdin = process2.stdin, _stdout = process2.stdout) { L12166: this._stdin = _stdin;
Critical
Credential Exfiltration

Source appears to send environment or credential material to an external endpoint.

dist/index.jsView on unpkg · L1225
1225// validation function arguments L1226: data: new codegen_1.Name("data"), L1227: // data passed to validation function ... L2252: id = normalizeId(id); L2253: return resolver.resolve(baseId, id); L2254: } ... L3112: for (i = 0; i < input.length; i++) { L3113: code = input[i].charCodeAt(0); L3114: if (code === 48) { ... L12164: var StdioServerTransport = class { L12165: constructor(_stdin = process2.stdin, _stdout = process2.stdout) { L12166: this._stdin = _stdin;
Critical
Command Output Exfiltration

Source executes local commands and sends command output to an external endpoint.

dist/index.jsView on unpkg · L1225
1225Trigger-reachable chain: manifest.main -> dist/index.js L1225: // validation function arguments L1226: data: new codegen_1.Name("data"), L1227: // data passed to validation function ... L2252: id = normalizeId(id); L2253: return resolver.resolve(baseId, id); L2254: } ... L3112: for (i = 0; i < input.length; i++) { L3113: code = input[i].charCodeAt(0); L3114: if (code === 48) { ... L12164: var StdioServerTransport = class { L12165: constructor(_stdin = process2.stdin, _stdout = process2.stdout) { L12166: this._stdin = _stdin;
Critical
Trigger Reachable Dangerous Capability

A package entrypoint or install-time lifecycle script reaches a source file with blocking dangerous behavior.

dist/index.jsView on unpkg · L1225
19607// src/application/git-repo-detect.ts L19608: import { execFileSync } from "node:child_process"; L19609: import path6 from "node:path";
High
Child Process

Package source references child process execution.

dist/index.jsView on unpkg · L19607
2941sourceCode = this.opts.code.process(sourceCode, sch); L2942: const makeValidate = new Function(`${names_1.default.self}`, `${names_1.default.scope}`, sourceCode); L2943: const validate = makeValidate(this, this.scope.get());
Low
Eval

Package source references a known benign dynamic code generation pattern.

dist/index.jsView on unpkg · L2941
dist/server.jsView file
9const __dirname = path.dirname(fileURLToPath(import.meta.url)); L10: const require = createRequire(import.meta.url); L11: const streamableHttpPath = path.join(__dirname, '..', 'node_modules', '@modelcontextprotocol', 'sdk', 'dist', 'esm', 'server', 'streamableHttp.js');
Medium
Dynamic Require

Package source references dynamic require/import behavior.

dist/server.jsView on unpkg · L9

Findings

3 Critical2 High4 Medium7 Low
CriticalCredential Exfiltrationdist/index.js
CriticalCommand Output Exfiltrationdist/index.js
CriticalTrigger Reachable Dangerous Capabilitydist/index.js
HighChild Processdist/index.js
HighShell
MediumDynamic Requiredist/server.js
MediumNetwork
MediumEnvironment Vars
MediumStructural Risk Force Deep Review
LowNon Install Lifecycle Scripts
LowScripts Present
LowEvaldist/index.js
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings
LowNo License