업데이트로 돌아가기
New releaseAug 21, 2026

mcp-stdio-shellguard v0.1.2

MCP stdio 서버용 심층 방어 번들: 드롭인 guardExec/guardSpawn 래퍼, AST 감사 CLI, 레퍼런스 MCP 서버. Ox-Security 200k 서버 stdio-RCE 클래스(LiteLLM CVE-2025-69256)를 차단합니다. MIT, TypeScript, Node >= 20.

공유

StudioMeyer MCP Stack의 일부 — 마요르카에서 제작 🌴 · 사용한다면 ⭐

mcp-stdio-shellguard

npm version npm downloads License Last commit GitHub stars

MCP stdio 서버를 위한 심층 방어(Defense-in-depth) 번들입니다. `child_process.exec/spawn`을 허용 목록(allowlist) + 샌드박스(sandbox) + 재생 감지(replay-detection)로 래핑하고, MCP 서버 소스에서 정화(sanitize)되지 않은 셸 호출을 스캔하는 AST 감사 CLI(`mcp-shellguard-audit`)도 포함합니다. Ox-Security MCP stdio-RCE 클래스를 차단합니다(2026년 5월 공개, 취약 서버 20만 개).
  • MCP 스펙: 2025-06-18
  • SDK: @modelcontextprotocol/sdk ^1.29.0
  • Node: >= 20
  • 라이선스: MIT
  • 저자: Matthias Meyer (StudioMeyer)

설치

npm install mcp-stdio-shellguard

또는 설치 없이 감사 CLI를 직접 실행:

npx -y -p mcp-stdio-shellguard mcp-shellguard-audit scan ./src

제공 기능

세 가지 계층으로, 부분적으로 선택 적용(opt-in)할 수 있습니다:

  1. 라이브러리 API — 자체 MCP 서버에서 호출하는 드롭인 guardExec / guardSpawn. 기본 거부(default-deny) 허용 목록, 샌드박스 프로파일, 재생 창(replay window).
  2. 감사 CLImcp-shellguard-audit scan <path>가 AST를 탐색하여 LOW(no timeout)부터 CRITICAL(exec(\...${userInput}...`)`)까지 12가지 안티패턴을 보고합니다.
  3. 참조 MCP 서버mcp-stdio-shellguard-demo는 8개의 도구를 노출하여 MCP Inspector / Claude Desktop이 번들을 직접 구동할 수 있게 합니다.

도구 (참조 서버)

도구유형용도
guard_exec파괴적방어된 child_process.exec. args[] 벡터를 강제하고 허용 목록 + 샌드박스 + 재생 감지를 적용합니다. stdout, stderr, exitCode, canonicalHash, isReplay, trustTier를 반환합니다.
guard_spawn파괴적방어된 child_process.spawn. 전체 본문 대신 stdout/stderr의 SHA-256 해시를 반환합니다. shell:true를 강하게 거부합니다.
register_allowlist변경형실행 파일 + 인자 regex로 도구 이름을 등록합니다. 등록하지 않으면 기본 거부(default-deny)가 적용됩니다.
audit_source읽기 전용TS/JS 경로에서 셸 인젝션 안티패턴을 스캔합니다. AuditFinding[] + 요약을 반환합니다.
audit_report읽기 전용감사 결과를 markdown / json / SARIF 2.1.0 형식으로 포맷합니다.
replay_check읽기 전용호출에 대한 표준 SHA-256 해시를 계산하고 재생 창에 이미 있는지 보고합니다.
sandbox_status읽기 전용활성 샌드박스 프로파일 + 구체적인 제한 + cgroup-v2 활성 플래그를 보고합니다.
trust_tier읽기 전용등록된 도구에 대한 LOW/MEDIUM/HIGH/CRITICAL 등급을 도출하고 개선 힌트를 제공합니다.

샌드박스 프로파일

프로파일타임아웃최대 stdout최대 stderrFD 예산cgroup-v2
strict5초1MB256KB32예 (cpu/memory)
standard (기본값)30초10MB1MB256
permissive5분100MB10MB1024아니요

호출자는 timeoutMs / fdBudget로 호출별 제한을 더 강화할 수 있습니다. 호출자는 프로파일을 넘어 제한을 완화할 수 없습니다.

신뢰 등급

등급조건
LOW도구가 등록되지 않음 (기본 거부)
MEDIUM등록되었지만 argsPatterns가 비어 있음 (모든 인자 허용)
HIGHargsPatterns가 설정되었지만 샌드박스 또는 재생 추적기가 비활성
CRITICALargsPatterns + sandbox + replay 모두 활성

도구 등록 + argsPatterns 설정 + guardExec/guardSpawn을 통한 실행(항상 sandbox + replay를 활성화함)으로 LOW → CRITICAL로 끌어올릴 수 있습니다.

라이브러리 빠른 시작

import {
  AllowlistRegistry,
  ReplayWindow,
  guardExec,
} from "mcp-stdio-shellguard";

const registry = new AllowlistRegistry();
const replay = new ReplayWindow();

registry.register({
  toolName: "git-log",
  executable: "/usr/bin/git",
  argsPatterns: ["^log$", "^--oneline$", "^-n$", "^\\d+$"],
  sandboxProfile: "strict",
});

const result = await guardExec(
  {
    toolName: "git-log",
    command: "/usr/bin/git",
    args: ["log", "--oneline", "-n", "10"],
  },
  { registry, replay },
);

console.log(result.stdout); // → commit lines
console.log(result.trustTier); // → "CRITICAL"
console.log(result.canonicalHash); // → 64-char SHA-256

감사 CLI

mcp-shellguard-audit scan ./src
mcp-shellguard-audit scan ./src --format sarif --output audit.sarif
mcp-shellguard-audit scan ./src --severity-floor HIGH    # CI gate

종료 코드:

  • 0 깨끗함 (플로어 이상의 발견 사항 없음)
  • 1 발견 사항 존재
  • 2 파싱 / IO 오류

안티패턴 라이브러리 (12가지 규칙)

ID심각도트리거 조건
exec_template_literal_with_inputCRITICALchild_process.exec(\ls ${x}`)`
exec_dynamic_stringCRITICALchild_process.exec(cmd)
exec_sync_dynamic_stringCRITICALchild_process.execSync(cmd)
eval_near_child_processCRITICALeval(...)
function_constructor_near_child_processCRITICALnew Function(...)
spawn_dynamic_file_argsHIGHspawn(bin, userArgs)
exec_file_dynamicHIGHexecFile(bin, ...)
shell_true_optionHIGH{ shell: true }
os_system_equivalentHIGHDeno.run / Bun.spawn
spawn_literal_dynamic_argsMEDIUMspawn('git', userArgs)
unbounded_bufferLOWmaxBuffer 없는 exec
missing_timeoutLOWtimeout 없는 exec/spawn

스캐너는 매칭 전에 이름이 바뀐 child_process 바인딩을 해석하므로, 아래의 위험한 형태는 호출이 리터럴 child_process.exec가 아닌 별칭(alias)을 통해 이루어져도 감지됩니다:

  • const execAsync = promisify(exec); execAsync(...${x})
  • import cp from "node:child_process"; cp.exec(...${x})
  • const { exec: sh } = require("child_process"); sh(...${x})
  • import { exec as run } from "node:child_process"; run(...)

동기식 변형(spawnSync, execFileSync)은 비동기 규칙을 공유하며, shell_true_option은 리터럴 { shell: true }뿐만 아니라 문자열 셸({ shell: "/bin/sh" }) 또는 동적 셸 값에서도 발생합니다. child_process가 아닌 함수의 promisify, 다른 모듈에서의 구조 분해, { shell: false }는 깨끗하게 유지됩니다(오탐 없음).

프래그마

  • // shellguard:ignore-next-line — 발견 사항 1건을 억제합니다
  • // shellguard:ignore-file — 전체 파일을 억제합니다 (드묾; 줄 단위 권장)

왜 필요한가

Ox-Security는 (2026-05) 20만 개 이상의 MCP stdio 서버가 LLM 도구 인자에서 직접 가져온 사용자 입력을 담은 템플릿 리터럴로 child_process.exec를 래핑한다고 공개했습니다. LiteLLM v1.83.6이 대표적인 사례였습니다(CVE는 1.83.7에서 패치됨). 이 번들은 방어 보안(defensive-security) 대응책입니다: 해당 클래스를 차단하는 드롭인 가드 + 스캐너. AWS Linux seccomp + Chromium 샌드박스 등급에서 영감을 받았습니다.

함께 보기

라이선스

MIT — Copyright (c) 2026 Matthias Meyer (StudioMeyer)

카테고리