Doramagic Project Pack · Human Manual

decoy-scan

Related topics: Installation and Quick Start, Security Checks and Detection

Overview

Related topics: Installation and Quick Start, Security Checks and Detection

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Tool Risk Tiers

Continue reading this section for the full explanation and source context.

Section Poisoning Pattern Categories

Continue reading this section for the full explanation and source context.

Section Pretty Print (Default)

Continue reading this section for the full explanation and source context.

Related topics: Installation and Quick Start, Security Checks and Detection

Overview

decoy-scan is a command-line security scanner for the MCP (Model Context Protocol) ecosystem. It identifies security risks in MCP server configurations, detects prompt injection attacks, analyzes dangerous tool permissions, and maps findings to the OWASP Agentic Top 10 security framework. The tool operates with zero dependencies, requiring only Node.js 18+, and needs no installation, account, or configuration to run.

Sources: README.md:1

Purpose and Scope

The primary purpose of decoy-scan is to proactively discover security vulnerabilities in MCP server configurations before attackers can exploit them. The tool addresses a critical gap in the MCP supply chain by providing automated security scanning that was previously unavailable to developers and security teams.

Key objectives:

  • Scan local MCP client configurations (Claude Desktop, Cursor, Windsurf, VS Code, Claude Code, Zed, Cline)
  • Classify tool risk levels based on name patterns and description analysis
  • Detect prompt injection attacks hidden within tool descriptions
  • Identify environment variable exposure and credential leakage
  • Analyze toxic data flows across server boundaries
  • Provide machine-readable output (JSON, SARIF) for CI/CD integration

Sources: README.md:1-5

Architecture Overview

decoy-scan follows a modular architecture where a single ES module (index.mjs) contains all core functionality without external dependencies.

graph TD
    A[User runs decoy-scan] --> B[Discover MCP Configs]
    B --> C[Parse Server Configurations]
    C --> D[Probe Servers via stdio]
    D --> E{Analysis Engine}
    
    E --> F[Tool Risk Classification]
    E --> G[Poisoning Detection]
    E --> H[Command Analysis]
    E --> I[Env Exposure Check]
    E --> J[Readiness Analysis]
    E --> K[Advisory Cross-Reference]
    
    F --> L[Aggregate Results]
    G --> L
    H --> L
    I --> L
    J --> L
    K --> L
    
    L --> M[Output Formatter]
    M --> N[Pretty Print / JSON / SARIF]

The scan orchestrator (scan()) coordinates all analysis modules and produces structured output. Each module operates independently, allowing the tool to continue analysis even if individual checks fail.

Sources: CONTRIBUTING.md:14-29

Core Security Checks

decoy-scan performs multiple simultaneous security checks across different attack vectors:

Check CategoryWhat it Detects
Tool Risk ClassificationCritical/high/medium/low tools by name and description
Prompt Injection Detection37 patterns across 20 attack categories in tool descriptions
Toxic Flow AnalysisCross-server data leak (TF001) and destructive (TF002) attack chains
Tool Manifest HashingTool additions, removals, and description changes between scans
Skill ScanningPrompt injection, hardcoded secrets, suspicious URLs in Claude Code skills
Server Command AnalysisPipe-to-shell, inline code, typosquatting, temp directory spawning
Environment Variable ExposureAPI keys, tokens, secrets, cloud credentials passed to servers
Supply Chain Advisories40+ known vulnerable MCP packages via Decoy advisory database
Transport SecurityHTTP without TLS, missing auth, wildcard CORS, public-bound SSE
Input SanitizationUnconstrained parameters, missing maxLength, open schemas
Permission ScopeOver-privileged servers, dangerous capability combinations
OWASP MappingEvery finding mapped to ASI01–ASI05

Sources: README.md:58-70

Tool Risk Tiers

Tools are classified into four risk tiers based on their potential impact:

TierRisk LevelDescriptionExamples
CriticalCan execute code, modify data, or cause irreversible changesexecute_command, write_file, delete_database
HighCan read files, make network requests, or access sensitive dataread_file, fetch_url, get_credentials
MediumModerate scope with limited blast radiuslist_directory, search_logs
LowMinimal risk, read-only or sandboxed operationsping, get_status

Sources: AGENTS.md:30-40

Poisoning Pattern Categories

The scanner detects 37 distinct prompt injection patterns organized into 20 attack categories:

graph LR
    A[Tool Description] --> B[Poisoning Detection Engine]
    
    B --> C[Instruction Override]
    B --> D[Concealment]
    B --> E[Data Exfiltration]
    B --> F[Credential Harvesting]
    B --> G[Coercive Execution]
    B --> H[Tool Shadowing]
    B --> I[Evasion Techniques]
    
    C --> J[Findings with Severity]
    D --> J
    E --> J
    F --> J
    G --> J
    H --> J
    I --> J

Sources: CONTRIBUTING.md:30-45

Supported MCP Hosts

decoy-scan automatically discovers and scans MCP configurations across multiple clients. Config paths are platform-aware for macOS, Windows, and Linux.

HostPlatform SupportConfig Location
Claude DesktopmacOS, Windows, LinuxPlatform-specific config directory
CursormacOS, Windows, LinuxPlatform-specific config directory
WindsurfmacOS, Windows, LinuxPlatform-specific config directory
VS CodemacOS, Windows, LinuxPlatform-specific config directory
Claude CodemacOS, Windows, LinuxPlatform-specific config directory
ZedmacOS, Windows, LinuxPlatform-specific config directory
ClinemacOS, Windows, LinuxPlatform-specific config directory

The tool also supports project-level .mcp.json configuration files when run from a project root.

Sources: AGENTS.md:85-93

Output Formats

decoy-scan provides multiple output formats to support different use cases:

Pretty Print (Default)

Human-readable output with colored severity badges and visual hierarchy:

▸ Discovering MCP servers…
▸ Running 12 checks…

✗ server-name 2 critical
  Critical tools: execute_command, write_file
  
✓ another-server passed

3 issues found · 2 critical, 1 high · 12 checks passed · 2.3s

JSON Output

Machine-readable format with full structural data:

{
  "timestamp": "ISO-8601",
  "hosts": ["Claude Desktop", "Cursor"],
  "servers": [{
    "name": "server-name",
    "hosts": ["Claude Desktop"],
    "command": "npx",
    "args": ["@modelcontextprotocol/server-filesystem"],
    "tools": [{
      "name": "read_file",
      "description": "...",
      "risk": "high",
      "poisoning": [{ "type": "...", "severity": "...", "description": "..." }]
    }],
    "risk": "high",
    "error": null,
    "findings": [{
      "type": "env-exposure",
      "severity": "high",
      "description": "...",
      "source": "env-config"
    }]
  }],
  "summary": {
    "total": 2,
    "critical": 1,
    "high": 1,
    "medium": 0,
    "low": 0,
    "poisoned": 0
  }
}

SARIF Output

Standard format for CI/CD integration with GitHub Security tab:

{
  "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.json",
  "version": "2.1.0",
  "runs": [{
    "tool": { "driver": { "name": "decoy-scan", "version": "0.7.0" } },
    "results": [...]
  }]
}

Brief Output

Minimal summary for agent consumption:

{
  "servers": 3,
  "critical": 1,
  "high": 2,
  "medium": 4,
  "low": 5,
  "poisoned": 0,
  "status": "fail",
  "exitCode": 2
}

Sources: AGENTS.md:65-84

Exit Codes

The tool uses standardized exit codes for programmatic integration:

Exit CodeMeaningTriggers
0No critical or high-risk issuesClean scan
1High-risk issues foundHigh-risk tools or findings
2Critical issues, tool poisoning, toxic flows, or policy violationCritical tools, prompt injection detected, or policy failure

The exit code is also surfaced as exitCode on --json and --brief output for agent branching without re-deriving severity from summary counts.

Sources: AGENTS.md:75-80

Command-Line Interface

Basic Usage

npx decoy-scan                        # Full scan
npx decoy-scan --json                 # Machine-readable output
npx decoy-scan --sarif                # SARIF 2.1.0 for CI/CD
npx decoy-scan --verbose              # Show all tools including low-risk
npx decoy-scan --brief                # Minimal summary

Explain Subcommand

For resolving what a scan finding means without parsing full scan output:

decoy-scan explain critical              # Severity tier
decoy-scan explain tool-description      # Finding category
decoy-scan explain prompt-override       # Poisoning type
decoy-scan explain read_file             # Tool name
decoy-scan explain list                  # Enumerate all explainable targets
decoy-scan explain <target> --json       # Structured output

Global Flags

FlagShortDescription
--verbose-vShow all tools including low-risk
--quiet-qSuppress status output
--version-VPrint version
--help-hPrint help

Sources: AGENTS.md:10-28

GitHub Action Integration

The official GitHub Action enables automated scanning on push and pull request events:

name: MCP Security
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: decoy-run/decoy-scan@v1

Action Inputs

InputDefaultDescription
policyno-critical,no-poisoningComma-separated policy rules
sariftrueUpload SARIF to GitHub Security tab
reportfalseUpload to Decoy Guard dashboard
tokenDecoy API token (for report)
verbosefalseShow all tools including low-risk

Policy Rules

no-critical          Fail on critical tools (code exec, file write)
no-high              Fail on high-risk tools (file read, network)
no-poisoning         Fail on prompt injection in tool descriptions
no-toxic-flows       Fail on cross-server data leak / destructive chains
no-secrets           Fail on secrets exposed in MCP config
require-tripwires    Fail if decoy-tripwire not installed
max-critical=N       Fail if more than N critical tools found

Sources: README.md:88-108

Library API

decoy-scan can be imported as a module for programmatic use:

import {
  scan,
  toSarif,
  classifyTool,
  detectPoisoning,
  analyzeToxicFlows,
  hashToolManifest,
  detectManifestChanges,
  discoverSkills,
  analyzeSkill,
} from 'decoy-scan';

const results = await scan({ skills: true });
console.log(results.toxicFlows);    // [{ id: "TF001", severity: "critical", roles: {...} }]
console.log(results.skills);        // [{ name: "...", findings: [...] }]
console.log(results.servers[0].manifestHash);  // "45c4c571f03c78a2"

Sources: README.md:55-63

Design Principles

The project adheres to strict architectural constraints that differentiate it from similar tools:

PrincipleImplementation
Zero dependenciesNode.js builtins only. No npm packages.
No build stepRaw ES modules. No TypeScript, no bundler.
Fast executionScan completes in seconds. Servers timeout aggressively.
Safe operationRead-only scanning. Never modifies configs. Kills spawned servers promptly.
Agent-firstJSON and SARIF output are machine-parseable. AGENTS.md is comprehensive.

These principles ensure the tool remains reliable, auditable, and easy to deploy across different environments.

Sources: CONTRIBUTING.md:90-98

Version History

VersionRelease DateKey Additions
0.7.02026-05-10v2 telemetry envelope, retry + persistent queue, first-run dashboard link
0.6.22026-05-10Fixed telemetry for empty config scenarios
0.5.82026-05-06GitHub star ask
0.5.72026-04-28Fixed dashboard links for token setup
0.5.62026-04-28Exit code in JSON output, --brief implies --json
0.5.52026-04-25Pretty CLI output overhaul, fixed code-execution tool classification
0.5.42026-04-25Fixed explain --json second payload bug
0.5.02026-04-21Added explain subcommand
0.2.02026-03-20SSE transport security, input sanitization, dynamic tripwire detection
0.1.02026-03-15Initial release

Sources: CHANGELOG.md:1-30

Comparison with Similar Tools

Featuredecoy-scanSnyk agent-scan
LanguageJavaScriptPython
Dependencies015 (aiohttp, pydantic, mcp, etc.)
Installnpx decoy-scanuvx snyk-agent-scan
MCP Hosts7 (Claude Desktop, Cursor, Windsurf, VS Code, Claude Code, Zed, Cline)Varies
OWASP MappingASI01–ASI05Limited

Sources: README.md:64-67

Sources: README.md:1

Installation and Quick Start

Related topics: Overview, CLI Reference

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Method 1: Direct Execution (Recommended)

Continue reading this section for the full explanation and source context.

Section Method 2: GitHub Action (CI/CD)

Continue reading this section for the full explanation and source context.

Section Method 3: Local Clone (Development)

Continue reading this section for the full explanation and source context.

Related topics: Overview, CLI Reference

Installation and Quick Start

Overview

decoy-scan is a zero-dependency MCP (Model Context Protocol) supply chain security scanner. It requires no installation, no configuration, and no account to begin scanning. Users can run it directly via npx or clone the repository for development purposes.

The tool scans local MCP client configurations across seven supported hosts, analyzes server commands for security risks, detects prompt injection in tool descriptions, and provides structured output for CI/CD integration.

Sources: README.md:1-5

System Requirements

RequirementSpecification
RuntimeNode.js 18+
Package ManagerNot required
Build ToolsNot required
OS SupportmacOS, Windows, Linux

The tool uses only Node.js built-in modules. No external npm packages are installed or required.

Sources: CONTRIBUTING.md:10

Installation Methods

The fastest way to run decoy-scan is through npx, which downloads and executes the package without affecting local dependencies:

npx decoy-scan

This single command discovers all MCP configurations on the machine, probes configured servers, and produces a security report.

Sources: README.md:14

Method 2: GitHub Action (CI/CD)

For automated security scanning in repositories, use the official GitHub Action:

name: MCP Security
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: decoy-run/decoy-scan@v1

The action supports configurable policy enforcement and SARIF output uploads to the GitHub Security tab.

Sources: action.yml:1-20

Method 3: Local Clone (Development)

For contributing or modifying the scanner:

git clone https://github.com/decoy-run/decoy-scan
cd decoy-scan
node bin/cli.mjs --help

No build step is required. The codebase uses raw ES modules with no bundler or TypeScript compilation.

Sources: CONTRIBUTING.md:5-9

Quick Start Workflow

graph TD
    A[Run npx decoy-scan] --> B{Node.js installed?}
    B -->|No| C[Install Node.js 18+]
    C --> A
    B -->|Yes| D[Discover MCP Configs]
    D --> E[Supported Hosts Found?]
    E -->|No| F[Print empty discovery message]
    E -->|Yes| G[Probe MCP Servers]
    G --> H[Analyze Tool Risk]
    H --> I[Detect Poisoning Patterns]
    I --> J[Check Environment Exposure]
    J --> K[Generate Report]
    K --> L{Human or CI Mode?}
    L -->|Human| M[Pretty Print Output]
    L -->|CI| N[JSON or SARIF Output]

Supported MCP Hosts

decoy-scan automatically discovers configurations for the following MCP clients:

HostPlatform Support
Claude DesktopmacOS, Windows, Linux
CursormacOS, Windows, Linux
WindsurfmacOS, Windows, Linux
VS CodemacOS, Windows, Linux
Claude CodemacOS, Windows, Linux
ZedmacOS, Windows, Linux
ClinemacOS, Windows, Linux

Config paths are platform-aware, detecting macOS, Windows, and Linux configuration locations automatically.

Sources: AGENTS.md:45-50

Command Line Interface

Basic Usage

CommandDescription
npx decoy-scanFull scan with pretty CLI output
npx decoy-scan --jsonMachine-readable JSON output
npx decoy-scan --sarifSARIF 2.1.0 format for CI/CD

Sources: AGENTS.md:6-8

Output Modes

#### Pretty Output (Default)

Human-readable format with color-coded severity badges and per-server summaries:

✗ server-name N critical
! server-name poisoned tool
✓ server-name passed

#### JSON Output

Structured machine-readable format for programmatic consumption:

{
  "timestamp": "ISO-8601",
  "hosts": ["Claude Desktop", "Cursor"],
  "servers": [{
    "name": "server-name",
    "tools": [{
      "name": "read_file",
      "risk": "high",
      "poisoning": []
    }],
    "risk": "high"
  }],
  "summary": {
    "total": 2,
    "critical": 1,
    "high": 2
  }
}

#### SARIF Output

Standardized format for integration with security tools and GitHub Security tab:

npx decoy-scan --sarif | jq

Sources: AGENTS.md:52-85

Common Flags

FlagShortDescription
--jsonMachine-readable JSON output
--sarifSARIF 2.1.0 output format
--briefMinimal summary (implies --json)
--verbose-vShow all tools including low-risk
--quiet-qSuppress status output
--no-probeConfig-only scan, skip server probing
--no-advisoriesSkip network calls to advisory database
--help-hPrint help message
--version-VPrint version

Sources: AGENTS.md:22-32

Exit Codes

The CLI returns exit codes for programmatic error handling:

CodeMeaning
0No critical or high-risk issues
1High-risk issues found
2Critical issues, tool poisoning, toxic flows, or policy violation

The exitCode field is also surfaced in --json and --brief output for agent consumption.

Sources: AGENTS.md:35-45

GitHub Action Configuration

Action Inputs

InputDefaultDescription
policyno-critical,no-poisoningComma-separated policy rules
sariftrueUpload SARIF to GitHub Security tab
reportfalseUpload to Decoy Guard dashboard
tokenDecoy API token (required for report)
verbosefalseShow all tools including low-risk

Policy Rules

no-critical          Fail on critical tools (code exec, file write)
no-high              Fail on high-risk tools (file read, network)
no-poisoning         Fail on prompt injection in tool descriptions
no-toxic-flows       Fail on cross-server data leak / destructive chains
no-secrets           Fail on secrets exposed in MCP config
require-tripwires    Fail if decoy-tripwire not installed
max-critical=N       Fail if more than N critical tools found

Full Example

name: MCP Security
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: decoy-run/decoy-scan@v1
        with:
          policy: no-critical,no-poisoning,no-toxic-flows
          sarif: true
          verbose: true

Sources: action.yml:1-30

Running Tests

Before submitting changes, run the full test suite to ensure all 48 tests pass:

npm test

Tests cover CLI output, JSON/SARIF structure, policy gates, toxic flow detection, skill analysis, and manifest hashing.

For manual testing with different output modes:

CommandPurpose
node bin/cli.mjs --no-probeConfig-only scan
node bin/cli.mjs --no-advisoriesSkip network calls
node bin/cli.mjs --jsonVerify JSON structure
node bin/cli.mjs --sarifVerify SARIF structure
node bin/cli.mjs --verboseShow everything

Sources: CONTRIBUTING.md:68-80

Project Structure

decoy-scan/
├── bin/
│   └── cli.mjs          # CLI entry point
├── index.mjs            # Core scanner logic
├── package.json         # Package metadata
└── *.test.mjs          # Test files

All scanner logic lives in index.mjs including:

SectionFunction
RISK_PATTERNS + classifyTool()Tool risk classification
POISONING_PATTERNS + detectPoisoning()Prompt injection detection
analyzeServerCommand()Server spawn command analysis
SENSITIVE_ENV_PATTERNS + analyzeEnvExposure()Environment variable exposure
analyzeReadiness()Production readiness heuristics
OWASP_MAP + mapToOwasp()OWASP Agentic Top 10 mapping
HOST_CONFIGS + discoverConfigs()MCP client config discovery
probeServer()MCP stdio probing
scan()Full scan orchestrator
toSarif()SARIF output generator

Sources: CONTRIBUTING.md:14-32

Design Principles

The installation and runtime model follows these principles:

  • Zero dependencies — Only Node.js built-ins are used. No npm packages added.
  • No build step — Raw ES modules executed directly.
  • Fast execution — Servers are probed with aggressive timeouts.
  • Read-only scanning — Configs are never modified; spawned servers are killed promptly.
  • Agent-first output — JSON and SARIF formats are machine-parseable.

Sources: CONTRIBUTING.md:82-88

Next Steps

After installation, explore these topics:

  1. Explain Command — Resolve finding types using decoy-scan explain <target>
  2. Output Formats — Understand JSON Schema and SARIF Schema
  3. What It Checks — Review the complete security checks list
  4. Contributing — Read CONTRIBUTING.md for development guidelines

Sources: README.md:1-5

System Architecture

Related topics: Core Modules Reference, Security Checks and Detection

Section Related Pages

Continue reading this section for the full explanation and source context.

Section 1. Configuration Discovery (discoverConfigs)

Continue reading this section for the full explanation and source context.

Section 2. Server Probing (probeServer)

Continue reading this section for the full explanation and source context.

Section 3. Security Analysis Engine

Continue reading this section for the full explanation and source context.

Related topics: Core Modules Reference, Security Checks and Detection

System Architecture

Overview

decoy-scan is a zero-dependency MCP (Model Context Protocol) supply chain security scanner built with Node.js >= 18. The architecture follows a modular design where a single index.mjs file contains all core analysis logic, while bin/cli.mjs provides the command-line interface. The tool discovers MCP server configurations from supported hosts, probes servers via stdio, and performs multi-layered security analysis.

Sources: CONTRIBUTING.md

Architecture Principles

The system is built on four core principles:

PrincipleDescription
Zero DependenciesNode.js builtins only; no npm packages
No Build StepRaw ES modules; no TypeScript or bundler
Fast ExecutionAggressive server timeouts; scan completes in seconds
Read-OnlyNever modifies configs; only reads and analyzes

Sources: CONTRIBUTING.md

High-Level System Flow

graph TD
    A[User invokes decoy-scan] --> B[Discover MCP Configs]
    B --> C{Hosts Found?}
    C -->|Yes| D[For each server]
    C -->|No| E[Log telemetry, exit]
    D --> F[Probe Server via stdio]
    F --> G[Analyze Tool List]
    G --> H{Analysis Results}
    H --> I[Security Findings]
    H --> J[Readiness Issues]
    I --> K[Generate Output]
    J --> K
    K --> L{Output Format}
    L -->|JSON| M[JSON to stdout]
    L -->|SARIF| N[SARIF to stdout]
    L -->|Pretty| O[Terminal formatting]
    K --> P[Send telemetry]
    P --> Q[Exit with code]

Core Components

1. Configuration Discovery (`discoverConfigs`)

The discovery module locates MCP server configurations across supported host applications. Configuration paths are platform-aware, supporting macOS, Windows, and Linux.

#### Supported Hosts

HostPlatform Support
Claude DesktopmacOS, Windows, Linux
CursormacOS, Windows, Linux
WindsurfmacOS, Windows, Linux
VS CodemacOS, Windows, Linux
Claude CodemacOS, Windows, Linux
ZedmacOS, Windows, Linux
ClinemacOS, Windows, Linux

Sources: AGENTS.md

#### Host Configuration Structure

"Claude Desktop": () => {
  const p = platform();
  if (p === "darwin") return join(homedir(), "path", "to", "config.json");
  if (p === "win32") return join(process.env.APPDATA || "", "path", "config.json");
  return join(homedir(), ".config", "path", "config.json");
}

Sources: CONTRIBUTING.md

2. Server Probing (`probeServer`)

The probing component spawns each MCP server via stdio protocol and queries its tool list. Servers are spawned with aggressive timeouts to ensure fast scanning.

#### Probe Behavior

  • Spawns server process with configured command and arguments
  • Sends initialize and tools/list requests via stdio
  • Captures tool definitions including name, description, and input schemas
  • Kills spawned servers promptly after receiving response
  • Records probe errors for failed servers

Sources: AGENTS.md

3. Security Analysis Engine

The analysis engine performs multi-layered security checks on discovered tools and server configurations.

#### 3.1 Tool Risk Classification (classifyTool)

Classifies every tool into risk tiers based on name patterns and description analysis:

Risk LevelDescriptionExamples
CriticalCan execute code, modify data, cause irreversible changesexecute_command, write_file, eval_code
HighFile read, network access, credential exposureread_file, fetch, run_sql
MediumEnvironment access, configuration changesget_env, set_config
LowRead-only, informationallist_files, get_time

#### Risk Pattern Matching

RISK_PATTERNS = {
  critical: [
    /^execute[_-]?(command|shell|code|script)$/i,
    /^run[_-]?(script|code|js|javascript|python|sql)$/i,
    /^eval[_-]?(script|code)$/i,
    /^evaluate[_-]?(script|code)$/i,
    // ... more patterns
  ],
  high: [
    /^read[_-]?(file|dir|directory)$/i,
    /^fetch[_-]?(url|http|https)?$/i,
    // ... more patterns
  ]
}

The classifier also uses substring fallback on lowercased names for tools without descriptions.

Sources: CONTRIBUTING.md

#### 3.2 Prompt Injection Detection (detectPoisoning)

Detects 37 regex patterns across 20 attack categories in tool descriptions:

CategoryDescription
Instruction OverrideTools that override system instructions
ConcealmentHidden or disguised malicious intent
Data ExfiltrationCredential or data stealing patterns
Credential HarvestingRequests for sensitive credentials
Coercive ExecutionForced execution patterns
Tool ShadowingImpersonation of legitimate tools
Evasion TechniquesPatterns to bypass detection

Each pattern includes:

  • pattern: Regex to match
  • type: Finding category (used for OWASP mapping)
  • severity: critical, high, medium, or low
  • description: Human-readable explanation

Sources: CONTRIBUTING.md

#### 3.3 Server Command Analysis (analyzeServerCommand)

Checks spawn commands for security issues:

CheckWhat it detects
Pipe-to-shellCommands using `` operators
Temp directoriesSpawning from /tmp or similar
Inline codeCommands with embedded scripts
TyposquattingSimilar names to popular packages
Network toolsSuspicious network utilities

#### 3.4 Environment Variable Analysis (analyzeEnvExposure)

Flags 12 categories of sensitive credentials passed to MCP servers:

CategoryExamples
API KeysOPENAI_API_KEY, ANTHROPIC_API_KEY
TokensGITHUB_TOKEN, AWS_TOKEN
PasswordsDB_PASSWORD, SERVICE_PASSWORD
Database URLsConnection strings with credentials
Cloud CredentialsAWS_SECRET, GCP_TOKEN

#### 3.5 Production Readiness (analyzeReadiness)

Checks for deployment readiness issues:

  • Missing tool descriptions
  • Missing input schemas
  • No required field validation
  • Overloaded tool scope
  • Destructive tools without safety hints

#### 3.6 OWASP Mapping (mapToOwasp)

Maps every finding to the OWASP Agentic Top 10 categories (ASI01–ASI05):

OWASP IDCategory
ASI01Agentic Access Control
ASI02Excessive Agency
ASI03hallucinations
ASI04Data Leakage
ASI05Overreliance

Sources: README.md

4. Scan Orchestration (`scan`)

The main orchestrator combines all analysis components:

async function scan({ skills = false } = {}) {
  // 1. Discover MCP configs from all hosts
  // 2. For each server, probe via stdio
  // 3. Run all analysis functions
  // 4. Collect findings
  // 5. Generate output based on format
  return {
    servers: [...],
    toxicFlows: [...],
    skills: [...],
    summary: {...}
  };
}

Sources: AGENTS.md

5. Output Generation

#### SARIF Output (toSarif)

Generates SARIF 2.1.0 compliant output for CI/CD integration:

{
  "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
  "version": "2.1.0",
  "runs": [{
    "results": [...],
    "tool": { "driver": { "name": "decoy-scan", "version": "..." }}
  }]
}

#### JSON Output Schema

{
  "timestamp": "ISO-8601",
  "hosts": ["Claude Desktop", "Cursor"],
  "servers": [{
    "name": "server-name",
    "hosts": ["Claude Desktop"],
    "command": "npx",
    "args": ["@modelcontextprotocol/server-filesystem"],
    "tools": [{
      "name": "read_file",
      "description": "...",
      "risk": "high",
      "poisoning": [{ "type": "...", "severity": "...", "description": "..." }]
    }],
    "risk": "high",
    "error": null,
    "findings": [{ "type": "env-exposure", "severity": "high", "description": "..." }]
  }],
  "summary": { "total": 2, "critical": 1, "high": 1 }
}

#### Brief Output Schema

{
  "servers": 3,
  "critical": 1,
  "high": 2,
  "medium": 4,
  "low": 5,
  "poisoned": 0,
  "status": "fail",
  "exitCode": 2
}

Sources: AGENTS.md

6. Telemetry System

The telemetry module (v2 envelope) collects anonymized usage data:

{
  schema_version: "2",
  event_id: "uuid",
  run_id: "uuid",
  ts: "ISO-8601",
  env: {
    node: "v20.x.x",
    platform: "darwin",
    arch: "x64",
    ci: false,
    host: "claude-desktop",
    locale: "en-US"
  }
}

#### Telemetry Features

FeatureDescription
Retry Logic1 retry with 200→800ms backoff
Persistent Queue~/.decoy/telemetry-queue.jsonl (FIFO, 1000 event cap)
Opt-outDECOY_TELEMETRY=0 or --no-telemetry flag
First-run NoticeCached at ~/.decoy/telemetry-notice-shown

Sources: CHANGELOG.md

CLI Architecture

graph TD
    A[CLI Entry: bin/cli.mjs] --> B[Parse Arguments]
    B --> C{Command?}
    C -->|explain| D[Explain Handler]
    C -->|scan| E[Scan Handler]
    C -->|login| F[Auth Handler]
    D --> G[Resolve against RISK_PATTERNS]
    E --> H[Initialize scan options]
    F --> I[Open browser to auth]
    H --> J[Call scan from index.mjs]
    J --> K[Format output]
    K --> L{Format?}
    L -->|json| M[JSON.stringify]
    L -->|sarif| N[toSarif]
    L -->|pretty| O[ANSI colors]
    L -->|brief| P[Summary object]
    M --> Q[Send telemetry]
    N --> Q
    O --> Q
    P --> Q
    Q --> R[Exit with code]

CLI Options

FlagDescription
--jsonMachine-readable JSON output
--sarifSARIF 2.1.0 for CI/CD
--briefMinimal summary object
--verbose, -vShow all tools including low-risk
--quiet, -qSuppress status output
--no-probeConfig-only scan (skip stdio)
--no-advisoriesSkip network calls
--explain <target>Explain severity/category/tool
--version, -VPrint version
--help, -hPrint help

Sources: AGENTS.md

Exit Codes

CodeMeaning
0No critical or high-risk issues
1High-risk issues found
2Critical issues, tool poisoning, toxic flows, or policy violation

Module Dependency Graph

graph LR
    A[bin/cli.mjs] --> B[index.mjs]
    B --> C[RISK_PATTERNS]
    B --> D[POISONING_PATTERNS]
    B --> E[HOST_CONFIGS]
    B --> F[SENSITIVE_ENV_PATTERNS]
    B --> G[OWASP_MAP]
    C --> H[classifyTool]
    D --> I[detectPoisoning]
    E --> J[discoverConfigs]
    F --> K[analyzeEnvExposure]
    G --> L[mapToOwasp]
    H --> M[scan]
    I --> M
    J --> M
    K --> M
    L --> M
    M --> N[toSarif]
    M --> O[JSON Output]
    M --> P[analyzeReadiness]
    M --> Q[analyzeServerCommand]

Library API

The module can be imported and used programmatically:

import {
  scan,
  toSarif,
  classifyTool,
  detectPoisoning,
  analyzeToxicFlows,
  hashToolManifest,
  detectManifestChanges,
  discoverSkills,
  analyzeSkill,
} from 'decoy-scan';

const results = await scan({ skills: true });
console.log(results.toxicFlows);    // [{ id: "TF001", severity: "critical", roles: {...} }]
console.log(results.skills);        // [{ name: "...", findings: [...] }]
console.log(results.servers[0].manifestHash);  // "45c4c571f03c78a2"

Sources: AGENTS.md

Additional Analysis Features

Toxic Flow Analysis

Detects cross-server data leak (TF001) and destructive (TF002) attack chains:

results.toxicFlows = [
  { id: "TF001", severity: "critical", roles: {...} },
  { id: "TF002", severity: "high", roles: {...} }
];

Skill Scanning

Analyzes Claude Code skills for:

  • Prompt injection in skill definitions
  • Hardcoded secrets
  • Suspicious URLs

Manifest Hashing

Tracks tool additions, removals, and description changes between scans:

results.servers[0].manifestHash  // "45c4c571f03c78a2"

Supply Chain Advisories

Cross-references against Decoy advisory database covering 40+ known vulnerable MCP packages.

Sources: README.md

GitHub Action Integration

graph LR
    A[GitHub Workflow] --> B[decoy-run/decoy-scan@v1]
    B --> C[Scan MCP Configs]
    C --> D{Policy Violation?}
    D -->|Yes| E[Fail Build]
    D -->|No| F[Upload SARIF]
    F --> G[GitHub Security Tab]

Action Inputs

InputDefaultDescription
policyno-critical,no-poisoningComma-separated policy rules
sariftrueUpload SARIF to GitHub Security tab
reportfalseUpload to Decoy Guard dashboard
tokenDecoy API token (for report)
verbosefalseShow all tools including low-risk

Policy Rules

no-critical          Fail on critical tools (code exec, file write)
no-high              Fail on high-risk tools (file read, network)
no-poisoning         Fail on prompt injection in tool descriptions
no-toxic-flows       Fail on cross-server data leak / destructive chains
no-secrets           Fail on secrets exposed in MCP config
require-tripwires    Fail if decoy-tripwire not installed
max-critical=N       Fail if more than N critical tools

Sources: README.md

Sources: CONTRIBUTING.md

Core Modules Reference

Related topics: System Architecture, Security Checks and Detection

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Severity Tiers

Continue reading this section for the full explanation and source context.

Section Pattern Anchoring

Continue reading this section for the full explanation and source context.

Section Poisoning Patterns

Continue reading this section for the full explanation and source context.

Related topics: System Architecture, Security Checks and Detection

Core Modules Reference

This reference documents the core modules that power decoy-scan's MCP security scanning engine. The tool uses a modular architecture with each library file handling a specific aspect of security analysis, from pattern matching to OWASP compliance mapping.

Architecture Overview

graph TD
    A[CLI Entry] --> B[scan orchestrator]
    B --> C[analyzers.mjs]
    B --> D[patterns.mjs]
    B --> E[tier.mjs]
    B --> F[owasp.mjs]
    B --> G[verify.mjs]
    C --> H[Tool Risk Classification]
    C --> I[Poisoning Detection]
    C --> J[Env Exposure Analysis]
    C --> K[Readiness Heuristics]
    H --> L[JSON/SARIF Output]
    I --> L
    J --> L
    K --> L

Module Responsibilities

ModulePrimary RoleKey Exports
analyzers.mjsSecurity analysis engineanalyzeServerCommand, analyzeEnvExposure, analyzeReadiness, probeServer
patterns.mjsPattern definitionsRISK_PATTERNS, POISONING_PATTERNS, SENSITIVE_ENV_PATTERNS
tier.mjsRisk tier classificationclassifyTool, severity tiers
owasp.mjsOWASP mappingOWASP_MAP, mapToOwasp
verify.mjsPolicy verificationSecurity policy enforcement

Risk Tier Classification (`tier.mjs`)

The tier.mjs module implements the classifyTool() function that evaluates MCP tools against predefined risk patterns. Tools are classified into four severity tiers:

graph LR
    A[Tool Name + Description] --> B[classifyTool]
    B --> C{pattern match}
    C -->|execute*| D[Critical]
    C -->|write*| D
    C -->|eval*| D
    C -->|read*| E[High]
    C -->|fetch*| E
    C -->|delete*| E
    C -->|search*| F[Medium]
    C -->|other| G[Low]

Severity Tiers

TierDescriptionExample ToolsExit Code Impact
CriticalCode execution, file write, data modificationexecute_command, write_file, evaluate_scriptExit code 2
HighFile read, network access, data deletionread_file, fetch_url, delete_recordExit code 1
MediumInformation retrieval, search operationssearch_files, list_directoryExit code 1
LowSafe, read-only operationsget_time, pingExit code 0

Sources: CONTRIBUTING.md

Pattern Anchoring

Critical patterns use anchoring (^ and $) to ensure exact matching. The module includes patterns for:

  • ^execute[_-]?(script|code|js|javascript|python|sql)$
  • ^evaluate[_-]?(script|code)$
  • ^run[_-]?(script|code|js|javascript|python|sql)$
  • ^eval[_-]?(script|code)$

Sources: CHANGELOG.md

Pattern Definitions (`patterns.mjs`)

The patterns.mjs module contains the security pattern definitions used across all analyzers.

Poisoning Patterns

Detects prompt injection attacks hidden in tool descriptions. The module defines 37 regex patterns across 20 attack categories:

CategorySeverityDescription
prompt-overrideCriticalDirect instruction override attempts
instruction-hijackCriticalHidden system prompt modifications
credential-harvestCriticalCredentials or tokens in descriptions
data-exfiltrationHighData extraction patterns
tool-shadowingHighTool name override patterns
concealmentMediumHidden/obfuscated content
coercive-executionHighForce execution patterns
evasion-techniquesMediumDetection evasion attempts

Sources: CONTRIBUTING.md, AGENTS.md

Pattern Structure

Each poisoning pattern follows this schema:

{
  pattern: /regex/i,           // Regex with case-insensitive flag
  type: "category-name",      // Finding type for OWASP mapping
  severity: "critical",       // critical, high, medium, low
  description: "Human-readable explanation"
}

Sensitive Environment Patterns

The SENSITIVE_ENV_PATTERNS constant identifies 12 categories of sensitive credentials:

CategoryExamples
API KeysOPENAI_API_KEY, ANTHROPIC_API_KEY, GITHUB_TOKEN
DatabaseDATABASE_URL, DB_PASSWORD, REDIS_URL
CloudAWS_SECRET_KEY, AZURE_KEY, GCP_TOKEN
AuthJWT_SECRET, SESSION_KEY, AUTH_TOKEN

Security Analyzers (`analyzers.mjs`)

The analyzers.mjs module contains the core analysis functions that evaluate MCP servers and their tools.

Server Command Analysis

The analyzeServerCommand() function examines how MCP servers are spawned:

  • Pipe-to-shell patterns (| sh, | bash)
  • Temp directory spawning (/tmp/, $TMPDIR)
  • Inline code execution
  • Typosquatting detection
  • Network tool usage

Environment Exposure Analysis

The analyzeEnvExposure() function scans environment variables passed to MCP servers, flagging:

  • Exposed API keys and tokens
  • Database connection strings
  • Cloud service credentials
  • Private authentication tokens

Production Readiness Analysis

The analyzeReadiness() function applies heuristics to evaluate production readiness:

// Readiness check pattern
if (/* condition */) {
  findings.push({
    type: "readiness-check-name",
    severity: "medium",
    description: "What's wrong and why it matters"
  });
}

Checks include:

  • Missing tool descriptions
  • Missing input schemas
  • Tools without required fields
  • Overloaded tool scope
  • Destructive tools without safety hints

Server Probing

The probeServer() function implements MCP stdio protocol probing:

  1. Spawns the server process
  2. Sends JSON-RPC initialize request
  3. Sends tools/list request
  4. Parses and returns tool manifest
  5. Terminates server process

OWASP Mapping (`owasp.mjs`)

The owasp.mjs module maps all findings to the OWASP Agentic Top 10 for 2026.

OWASP Categories

CodeCategoryDescription
ASI01Agentic Access ControlOver-privileged agent permissions
ASI02Tool PoisoningPrompt injection in tools
ASI03Data ExfiltrationCross-server data leaks
ASI04Unbounded Tool ExecutionTools without safeguards
ASI05Supply ChainVulnerable dependencies

Sources: README.md

Mapping Function

The mapToOwasp() function converts internal finding types to OWASP categories:

// After adding a pattern, add its type to OWASP_MAP
ASI02: ["prompt-override", "instruction-hijack", "credential-harvest"]

Policy Verification (`verify.mjs`)

The verify.mjs module enforces security policies defined via CLI flags.

Policy Rules

RuleAction
no-criticalFail if critical tools found
no-highFail if high-risk tools found
no-poisoningFail if prompt injection detected
no-toxic-flowsFail on cross-server attack chains
no-secretsFail on exposed secrets
require-tripwiresFail if decoy-tripwire not installed
max-critical=NLimit critical tool count

Verification Flow

graph TD
    A[Scan Results] --> B[verify.mjs]
    B --> C{Policy Check}
    C -->|no-critical| D{critical count > 0?}
    C -->|no-poisoning| E{poisoning detected?}
    C -->|no-toxic-flows| F{toxic flows found?}
    D -->|Yes| G[Exit Code 2]
    E -->|Yes| G
    F -->|Yes| G
    D -->|No| H[Continue]
    E -->|No| H
    F -->|No| H
    H --> I[Exit Code 0 or 1]

Integration Flow

sequenceDiagram
    participant CLI
    participant scan
    participant analyzers
    participant patterns
    participant owasp
    participant verify
    participant output

    CLI->>scan: scan({ options })
    scan->>analyzers: discoverConfigs()
    analyzers-->>scan: server configs
    scan->>analyzers: probeServer(server)
    analyzers-->>scan: tool manifest
    scan->>patterns: detectPoisoning(tools)
    patterns-->>scan: poisoning findings
    scan->>patterns: classifyTool(tool)
    patterns-->>scan: risk tier
    scan->>analyzers: analyzeEnvExposure()
    analyzers-->>scan: env findings
    scan->>owasp: mapToOwasp(findings)
    owasp-->>scan: OWASP mappings
    scan->>verify: checkPolicy(results)
    verify-->>CLI: exitCode
    scan->>output: toSarif(results)
    output-->>CLI: SARIF report

Export Summary

The library can be imported directly:

import {
  scan,
  toSarif,
  classifyTool,
  detectPoisoning,
  analyzeToxicFlows,
  hashToolManifest,
  detectManifestChanges,
  discoverSkills,
  analyzeSkill,
} from 'decoy-scan';

const results = await scan({ skills: true });

Key exports include:

  • scan() — Full scan orchestrator
  • toSarif() — SARIF 2.1.0 output generator
  • classifyTool() — Tool risk classification
  • detectPoisoning() — Prompt injection detection
  • analyzeToxicFlows() — Cross-server attack chain analysis
  • hashToolManifest() — Tool manifest hashing
  • detectManifestChanges() — Change tracking between scans

Sources: README.md

Sources: CONTRIBUTING.md

Security Checks and Detection

Related topics: Supply Chain and Advisory Database, Skill Scanning, Output Formats and Policy Configuration

Section Related Pages

Continue reading this section for the full explanation and source context.

Section 1. Tool Risk Classification

Continue reading this section for the full explanation and source context.

Section 2. Prompt Injection Detection

Continue reading this section for the full explanation and source context.

Section 3. Server Command Analysis

Continue reading this section for the full explanation and source context.

Related topics: Supply Chain and Advisory Database, Skill Scanning, Output Formats and Policy Configuration

Security Checks and Detection

Overview

decoy-scan implements a comprehensive multi-layered security detection system for MCP (Model Context Protocol) servers. The scanner analyzes MCP client configurations, probes running servers, and evaluates tools against various threat categories including prompt injection, credential exposure, dangerous command execution, and supply chain vulnerabilities.

Sources: README.md:37-51

The detection engine operates across eight primary security dimensions, providing both static configuration analysis and dynamic runtime probing to identify risks before they can be exploited.

Architecture Overview

graph TD
    A[MCP Client Configs] --> B[Config Discovery]
    B --> C[Server Command Analysis]
    B --> D[Environment Variable Analysis]
    C --> E[Server Probing]
    E --> F[Tool Risk Classification]
    E --> G[Poisoning Detection]
    E --> H[Readiness Checks]
    F --> I[Toxic Flow Analysis]
    G --> I
    H --> I
    I --> J[OWASP Mapping]
    J --> K[SARIF/JSON Output]
    D --> K

Detection Layers

1. Tool Risk Classification

The scanner classifies every discovered tool into severity tiers based on name patterns and description analysis. Risk levels follow a four-tier system:

TierRisk LevelDescriptionExit Code Impact
CriticalCriticalCan execute code, modify data, or cause irreversible changesExit code 2
HighHighFile system access, network operationsExit code 1
MediumMediumInformation disclosure potentialExit code 0
LowLowMinimal risk, read-only operationsExit code 0

Sources: AGENTS.md:85-90

#### Classification Mechanism

Tool classification uses the classifyTool() function which applies regex pattern matching against both tool names and descriptions. The RISK_PATTERNS object defines critical patterns including:

  • execute_command, run_shell, bash, exec — command execution
  • write_file, create_file, update_file — file modification
  • delete_file, remove_file — destructive operations
  • evaluate_script, execute_script, run_javascript, run_python, run_sql — code evaluation variants
  • spawn, fork, child_process — process spawning

Sources: CONTRIBUTING.md:15-16

The substring fallback mechanism matches against lowercased tool names, ensuring risky verbs like evaluate, spawn, and fetch classify correctly even when no description is provided.

2. Prompt Injection Detection

Prompt injection detection identifies malicious content hidden within tool descriptions. The system uses 37 regex patterns across 20 attack categories:

CategorySeverityDescription
instruction-overrideCriticalOverrides agent instructions
role-assumptionCriticalImpersonates system roles
concealed-commandsHighHidden command instructions
privilege-escalationHighAttempts to gain elevated access
context-manipulationMediumManipulates conversation context
data-exfiltrationHighExtracts sensitive information
credential-harvestingCriticalCollects authentication credentials
coercionHighForces specific behaviors
tool-shadowingCriticalMasks legitimate tool behavior

Sources: README.md:37-40

The detectPoisoning() function scans tool descriptions against POISONING_PATTERNS, identifying injection attempts that could compromise agent behavior.

#### Poisoning Pattern Structure

Each pattern in POISONING_PATTERNS follows this schema:

{
  pattern: /regex/i,           // Match criteria
  type: "category-name",       // Finding type for OWASP mapping
  severity: "critical",         // critical, high, medium, low
  description: "Human-readable" // Display message
}

Sources: CONTRIBUTING.md:33-40

3. Server Command Analysis

The analyzeServerCommand() function examines how MCP servers are spawned, detecting suspicious invocation patterns:

  • Pipe-to-shell patterns — Commands using | to pipe output to shell interpreters
  • Temp directory spawning — Servers running from /tmp or similar writable locations
  • Inline code execution — Commands with embedded code strings
  • Typosquatting detection — Package names similar to legitimate tools
  • Network tool usage — Presence of curl, wget, or other network utilities

This analysis operates on configuration data without requiring server execution.

4. Environment Variable Exposure Detection

The analyzeEnvExposure() function identifies sensitive environment variables being passed to MCP servers. It checks against SENSITIVE_ENV_PATTERNS covering 12 categories:

CategoryExamples
API KeysOPENAI_API_KEY, ANTHROPIC_API_KEY, AWS_ACCESS_KEY_ID
TokensGITHUB_TOKEN, GITLAB_TOKEN, SLACK_TOKEN
Database CredentialsDB_PASSWORD, POSTGRES_PASSWORD, MONGO_URI
Cloud CredentialsAWS_SECRET_ACCESS_KEY, AZURE_CLIENT_SECRET
Private KeysSSH_PRIVATE_KEY, GPG_KEY

Sources: CONTRIBUTING.md:21-22

5. Production Readiness Checks

The analyzeReadiness() function applies heuristics to evaluate production readiness:

CheckSeverityDescription
Missing descriptionsMediumTools without documentation
Missing schemasMediumTools without input validation schemas
No required fieldsMediumUnvalidated parameter acceptance
Overloaded scopeMediumTools performing multiple unrelated operations
Destructive tools without safety hintsLowDangerous operations lacking warnings

Sources: CONTRIBUTING.md:23-24

6. Toxic Flow Analysis

Toxic flow detection identifies dangerous cross-server data leakage patterns. Two primary flow types are detected:

Flow IDSeverityDescription
TF001CriticalCross-server data leak — data read by one server flows to another
TF002CriticalDestructive attack chain — combined operations cause irreversible damage

Sources: README.md:43-44

The analyzeToxicFlows() function examines the interaction patterns between multiple MCP servers to identify these attack vectors.

7. Tool Manifest Hashing

Manifest hashing tracks changes in the tool list exposed by MCP servers:

const results = await scan({ skills: true });
console.log(results.servers[0].manifestHash);  // "45c4c571f03c78a2"

The hashToolManifest() and detectManifestChanges() functions detect:

  • Tool additions (potential malicious injection)
  • Tool removals (potential functionality loss)
  • Description changes (potential poisoning updates)

Sources: AGENTS.md:101-105

8. Skill Scanning

For Claude Code environments, the scanner performs additional analysis on skills:

  • Prompt injection detection in skill prompts
  • Hardcoded secret detection
  • Suspicious URL identification

The discoverSkills() and analyzeSkill() functions implement this analysis.

OWASP Agentic Top 10 Mapping

All findings are mapped to the OWASP Agentic Top 10 for Agentic Applications using the mapToOwasp() function with OWASP_MAP. The mapping covers ASI01 through ASI05 categories:

OWASP CodeCategoryMapped From
ASI01Sensitive Action Without ConfirmationCritical tool findings
ASI02Tool PoisoningPoisoning pattern matches
ASI03Over-Privileged Tool ScopeReadiness check failures
ASI04Sandbox EscapeCommand execution patterns
ASI05Context Length ExhaustionHeavy tool descriptions

Sources: README.md:50

Scan Orchestration

The scan() function orchestrates all security checks in the following sequence:

graph LR
    A[Discover Hosts] --> B[Find Server Configs]
    B --> C[Analyze Commands]
    C --> D[Probe Servers]
    D --> E[Classify Tools]
    E --> F[Detect Poisoning]
    F --> G[Check Readiness]
    G --> H[Analyze Flows]
    H --> I[Map to OWASP]
    I --> J[Generate Output]

Output Formats

SARIF Output

The toSarif() function generates SARIF 2.1.0 format output suitable for CI/CD integration and GitHub Security tab uploads.

JSON Output Schema

{
  "timestamp": "ISO-8601",
  "hosts": ["Claude Desktop", "Cursor"],
  "servers": [{
    "name": "server-name",
    "hosts": ["Claude Desktop"],
    "command": "npx",
    "args": ["@modelcontextprotocol/server-filesystem"],
    "tools": [{
      "name": "read_file",
      "description": "...",
      "risk": "high",
      "poisoning": [{ "type": "...", "severity": "...", "description": "..." }]
    }],
    "risk": "high",
    "findings": [{
      "type": "env-exposure",
      "severity": "high",
      "description": "..."
    }]
  }],
  "summary": {
    "total": 2, "critical": 1, "high": 1
  }
}

Sources: AGENTS.md:53-71

Exit Codes

CodeMeaningCondition
0CleanNo critical or high-risk issues
1WarningHigh-risk issues found
2FailureCritical issues, tool poisoning, or toxic flows

The exitCode field is also surfaced in JSON and --brief output for programmatic consumption.

Policy Enforcement

The --policy flag enables CI/CD policy gates:

RuleBehavior
no-criticalFail on critical tools
no-highFail on high-risk tools
no-poisoningFail on prompt injection
no-toxic-flowsFail on cross-server leaks
no-secretsFail on exposed secrets
require-tripwiresFail if decoy-tripwire not installed

Sources: README.md:66-77

Explain Functionality

The explain subcommand provides context for findings without running a full scan:

decoy-scan explain critical          # Severity tier explanation
decoy-scan explain tool-description  # Finding category details
decoy-scan explain prompt-override   # Poisoning type explanation
decoy-scan explain evaluate_script   # Tool classification reasoning

Explanations resolve against the same patterns used by the scanner, ensuring consistency between detection and documentation.

CLI Integration

The GitHub Action integration provides automated security scanning:

- uses: decoy-run/decoy-scan@v1
  with:
    policy: no-critical,no-poisoning,no-toxic-flows
    sarif: true

Results are uploaded to the GitHub Security tab via the SARIF format.

Summary Table of Detection Capabilities

Detection TypeFunctionPatterns/ChecksExit Code
Tool RiskclassifyTool()Name + description matching0/1/2
PoisoningdetectPoisoning()37 regex patterns2
CommandanalyzeServerCommand()5 pattern categories1/2
Env ExposureanalyzeEnvExposure()12 credential categories1/2
ReadinessanalyzeReadiness()5 heuristic checks0/1
Toxic FlowsanalyzeToxicFlows()TF001, TF0022
Manifest HashhashToolManifest()Change detection1
Skill ScananalyzeSkill()Injection + secrets1/2

Sources: index.mjs, bin/cli.mjs

Sources: README.md:37-51

Supply Chain and Advisory Database

Related topics: Security Checks and Detection, Skill Scanning

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Advisory Database Integration

Continue reading this section for the full explanation and source context.

Section Advisory Data Structure

Continue reading this section for the full explanation and source context.

Section Network Layer

Continue reading this section for the full explanation and source context.

Related topics: Security Checks and Detection, Skill Scanning

Supply Chain and Advisory Database

Overview

The Supply Chain and Advisory Database module in decoy-scan provides security checks against a curated database of known vulnerable MCP packages. This feature enables automated cross-referencing of configured MCP servers against known supply chain threats, helping organizations identify and mitigate risks from third-party dependencies before attackers can exploit them.

The advisory system is designed to be non-intrusive and fast. It performs network lookups against the Decoy advisory database to fetch security intelligence about MCP packages, with built-in retry logic and offline fallbacks to ensure scanning reliability.

Architecture

graph TD
    A[scan] --> B[Discover MCP Configs]
    B --> C[For Each Server]
    C --> D[Probe Server via Stdio]
    D --> E[Fetch Tool List]
    E --> F[Run Security Checks]
    F --> G{Tool Risk Classification}
    F --> H{Poisoning Detection}
    F --> I{Supply Chain Advisories}
    
    I --> J[HTTP GET /api/advisories?<packages>]
    J --> K{API Available?}
    K -->|Yes| L[Cache Response]
    K -->|No| M[Retry 1x]
    M -->|Fail| N[Fallback to Local]
    
    L --> O[Apply Findings]
    N --> O

Core Components

Advisory Database Integration

The supply chain advisory system integrates with an external Decoy advisory database via HTTP API calls. When scanning MCP configurations, the system extracts package identifiers from server configurations and queries the advisory database for known vulnerabilities.

// Conceptual flow from index.mjs
const advisories = await fetchAdvisories(packageList);

Sources: index.mjs:scan()

Advisory Data Structure

Advisory records returned from the database contain the following fields:

FieldTypeDescription
packagestringNPM package name or MCP server identifier
severitystringcritical, high, medium, or low
titlestringBrief description of the vulnerability
descriptionstringDetailed advisory information
cvestringCVE identifier (if available)
recommendationstringSuggested remediation steps

Network Layer

The advisory fetcher implements resilient network handling:

sequenceDiagram
    participant Scanner
    participant API as Decoy API
    participant Cache
    
    Scanner->>API: GET /api/advisories?packages=...
    API-->>Scanner: 200 OK (advisory data)
    Scanner->>Cache: Store response
    Note over Scanner: 1 retry with 200-800ms backoff
    
    Scanner->>API: GET /api/advisories?packages=...
    API-->>Scanner: 5xx Error
    Scanner->>API: Retry after backoff
    API-->>Scanner: Still failing
    Scanner->>Scanner: Fallback to cached/local data

Sources: CHANGELOG.md:0.7.0

Configuration Options

CLI Flags

FlagDefaultDescription
--no-advisoriesfalseSkip supply chain advisory checks
--advisory-cache~/.decoy/advisory-cache.jsonLocal cache file path
--api-urlhttps://api.decoy.runOverride advisory API endpoint

Environment Variables

VariableDescription
DECOY_API_URLCustom API endpoint for advisory lookups
DECOY_API_TOKENAuthentication token for premium advisories

Advisory Categories

The Decoy advisory database covers multiple vulnerability categories relevant to MCP servers:

CategoryDescriptionExample
Code ExecutionVulnerabilities allowing arbitrary code executionMalicious npm package with postinstall script
Data ExfiltrationPackages that leak sensitive informationTelemetry packages with credential harvesting
Dependency ConfusionTyposquatting or substitution attacksmcp-server vs mc-p-server
Known ExploitsCVE-assigned vulnerabilities with active exploitationRemote code execution in popular MCP packages

Sources: README.md:What it checks

Scan Integration

Scan Categories

The supply chain advisory check is one of nine scan categories in decoy-scan:

CheckPriority
Tool risk classification1
Tool poisoning detection2
Supply chain advisories3
Server command analysis4
Environment variable exposure5
Production readiness6
Toxic flow analysis7
Manifest change tracking8
Transport security9

Sources: AGENTS.md:Scan Categories

Integration with Tool Classification

Advisory findings are combined with tool risk classification results to produce comprehensive security reports:

// Simplified integration flow
const toolRisk = classifyTool(toolName, toolDescription);
const advisoryInfo = await lookupAdvisory(serverPackage);
const combinedRisk = mergeRiskScores(toolRisk, advisoryInfo);

Sources: index.mjs:classifyTool()

Output Integration

JSON Output

Advisory findings appear in the JSON output under each server's findings array:

{
  "servers": [{
    "name": "example-mcp-server",
    "findings": [{
      "type": "supply-chain-advisory",
      "severity": "high",
      "package": "@example/mcp-server",
      "description": "Known vulnerability in version < 1.2.0",
      "cve": "CVE-2024-1234",
      "recommendation": "Upgrade to version 1.2.0 or later"
    }]
  }]
}

SARIF Output

Advisory findings are also exported in SARIF 2.1.0 format for CI/CD integration:

{
  "results": [{
    "ruleId": "decoy-advisory-HIGH-001",
    "level": "warning",
    "message": {
      "text": "Package @example/mcp-server has known vulnerability CVE-2024-1234"
    }
  }]
}

Sources: README.md:Structured output for agents

Telemetry and Analytics

The supply chain advisory system includes anonymized telemetry to help improve the advisory database:

EventPurpose
scan.discoveryRecords which hosts and servers were scanned
scan.completeFinal scan results including advisory findings
scan.uploadedIndicates when results were uploaded to dashboard

Telemetry includes environment metadata (Node version, platform, architecture) but no sensitive user data. Users can opt out via DECOY_TELEMETRY=0 or the --no-telemetry flag.

Sources: CHANGELOG.md:0.7.0

Performance Considerations

Timeout Configuration

Advisory API calls use aggressive timeouts to maintain scan performance:

SettingValueRationale
Connection timeout2000msFast failure on unreachable API
Read timeout5000msAllow for large response payloads
Retry attempts1Minimize latency impact

Caching Strategy

Advisory responses are cached locally to reduce API calls:

graph LR
    A[Scan Start] --> B{Cache Hit?}
    B -->|Yes| C[Use Cached Data]
    B -->|No| D[Query API]
    D --> E[Store in Cache]
    E --> C
    C --> F[Continue Scan]

Cache location is platform-aware:

PlatformCache Path
macOS~/.decoy/advisory-cache.json
Linux~/.decoy/advisory-cache.json
Windows%APPDATA%/.decoy/advisory-cache.json

Sources: AGENTS.md:Supported Hosts

Extensibility

Adding New Advisory Categories

To extend the advisory system with new vulnerability categories, modify the pattern definitions in the constants module:

// In lib/constants.mjs
export const ADVISORY_CATEGORIES = {
  // ... existing categories
  NEW_CATEGORY: {
    pattern: /new-vulnerability-pattern/i,
    severity: "medium",
    description: "Description of new vulnerability type"
  }
};

Custom Advisory Sources

Organizations can integrate private advisory databases by implementing a custom advisory fetcher:

import { createAdvisoryFetcher } from './lib/advisories.mjs';

const customFetcher = createAdvisoryFetcher({
  apiUrl: 'https://internal.advisories.example.com',
  apiToken: process.env.INTERNAL_ADVISORY_TOKEN
});

Sources: CONTRIBUTING.md:Code Structure

Exit Codes and Policy Enforcement

Advisory findings affect the scan exit code:

Exit CodeCondition
0No critical or high-risk issues, no advisories
1High-risk advisories found
2Critical advisories found

Policy gates can be configured via CLI:

decoy-scan --policy no-critical,no-high

Sources: README.md:Exit codes

See Also

Source: https://github.com/decoy-run/decoy-scan / Human Manual

Skill Scanning

Related topics: Security Checks and Detection, CLI Reference

Section Related Pages

Continue reading this section for the full explanation and source context.

Section discoverSkills()

Continue reading this section for the full explanation and source context.

Section analyzeSkill(skill)

Continue reading this section for the full explanation and source context.

Section Integration with scan()

Continue reading this section for the full explanation and source context.

Related topics: Security Checks and Detection, CLI Reference

Skill Scanning

Skill Scanning is a security analysis feature in decoy-scan that detects vulnerabilities within Claude Code skills. It scans skill definitions for prompt injection payloads, hardcoded secrets, and suspicious URLs that could compromise agent safety.

Overview

Skill Scanning operates as part of the broader MCP (Model Context Protocol) security assessment suite. While tool scanning analyzes the risk profile of MCP server tools, skill scanning focuses on identifying malicious content embedded within skill definitions that could be exploited during agent execution.

技能扫描与工具扫描的核心区别在于:工具扫描评估 MCP 服务器提供的工具能力风险,而技能扫描检查本地定义的技能文件中可能被恶意利用的内容。

Architecture

The skill scanning subsystem consists of three primary components that work together to provide comprehensive skill security analysis:

graph TD
    A[Skill Definitions] --> B[discoverSkills]
    B --> C{Skill Files Found?}
    C -->|Yes| D[analyzeSkill]
    C -->|No| E[Skip Analysis]
    D --> F[Skill Findings Array]
    F --> G[Integration into scan Results]
    
    H[Poisoning Patterns] --> D
    I[Secret Patterns] --> D
    J[URL Patterns] --> D

The architecture follows a two-phase approach: first discovering skill definitions across the filesystem, then analyzing each discovered skill for multiple categories of security issues.

Core Functions

discoverSkills()

The discoverSkills() function searches for Claude Code skill definition files in the project directory. It recursively traverses the filesystem to locate .mdc files that contain skill definitions.

PropertyValue
Function NamediscoverSkills
Modulelib/skills.mjs
Return TypePromise<Skill[]>
Side EffectsRead-only filesystem scan

技能发现采用递归目录遍历策略,从当前工作目录开始搜索 .mdc 扩展名的文件。

analyzeSkill(skill)

The analyzeSkill() function performs deep security analysis on an individual skill definition. It evaluates the skill content against multiple pattern sets to detect various attack vectors.

分析函数对每个技能执行三类安全检查:

  • 提示注入检测 (Prompt Injection Detection)
  • 硬编码密钥检测 (Hardcoded Secret Detection)
  • 可疑 URL 检测 (Suspicious URL Detection)

Integration with scan()

In the main scan orchestration, skills are discovered and analyzed when the skills option is enabled:

const results = await scan({ skills: true });
console.log(results.skills);  // [{ name: "...", findings: [...] }]

Sources: README.md

Finding Categories

Skill scanning identifies three primary categories of security issues:

Prompt Injection Detection

Detects prompt injection payloads hidden within skill descriptions. These attacks embed malicious instructions that could override agent behavior when the skill is executed.

SeverityDescription
CriticalActive prompt override instructions
HighConcealment techniques hiding true intent
MediumSubtle manipulation hints

Hardcoded Secrets

Identifies API keys, tokens, passwords, and other credentials accidentally embedded in skill definitions. This finding type aligns with OWASP credential exposure categories.

Suspicious URLs

Detects references to potentially malicious or untrusted URLs within skill content. URLs to external resources could lead agents to compromised servers or phishing pages.

Output Structure

When skill scanning is enabled, the scan results include a skills array containing analysis results for each discovered skill:

{
  "skills": [
    {
      "name": "skill-name",
      "path": "/path/to/skill.mdc",
      "findings": [
        {
          "type": "prompt-injection",
          "severity": "high",
          "description": "...",
          "source": "skill-content"
        }
      ]
    }
  ]
}

The skills findings are integrated into the overall scan results alongside tool risk classifications, poisoning detections, and toxic flow analysis.

Sources: README.md

Usage

CLI Usage

Skill scanning is enabled by default when running a full scan with skill analysis:

npx decoy-scan --verbose

The --verbose flag reveals all discovered skills and their findings, including those previously hidden in standard output.

Programmatic Usage

import { discoverSkills, analyzeSkill } from 'decoy-scan';

// Discover all skills in the project
const skills = await discoverSkills();

// Analyze each skill individually
for (const skill of skills) {
  const analysis = await analyzeSkill(skill);
  console.log(`${skill.name}: ${analysis.findings.length} issues`);
}

Configuration

Skill scanning behavior can be controlled through scan options:

OptionTypeDefaultDescription
skillsbooleantrueEnable/disable skill scanning
verbosebooleanfalseShow detailed skill findings

OWASP Mapping

Skill findings are mapped to the OWASP Agentic Top 10 categories where applicable:

Finding TypeOWASP Category
Prompt InjectionASI01 - Prompt Injection
Hardcoded SecretsASI04 - Sensitive Data Disclosure
Suspicious URLsASI02 - Visualization Overflow

The OWASP_MAP in the main scanner correlates skill finding types with their corresponding OWASP classifications for compliance reporting.

Sources: CONTRIBUTING.md

Discovery Process

The skill discovery process in lib/discovery.mjs locates Claude Code skill files through a structured search pattern:

  1. Directory Traversal: Recursively scan project directories
  2. Pattern Matching: Identify files matching skill definition patterns
  3. Path Resolution: Build absolute paths for discovered skills
  4. Metadata Extraction: Parse skill name and metadata from definitions

技能发现是只读操作,不会修改任何文件系统内容。所有发现的文件路径都被规范化为绝对路径以便后续分析。

Integration Points

Skill scanning integrates with several other decoy-scan subsystems:

  • Tool Manifest Hashing: Skills may reference tools whose manifests are hashed
  • SARIF Export: Skill findings appear in SARIF output under the appropriate rules
  • Policy Enforcement: no-secrets policy rules can target skill findings
  • Telemetry: Scan telemetry includes skill discovery counts

Testing

The test suite validates skill scanning behavior through unit.test.mjs which covers skill analysis patterns and findings generation. All skill-related tests must pass before PR submission.

npm test  # Runs 48 tests including skill scanning coverage

See Also

Sources: README.md

CLI Reference

Related topics: Installation and Quick Start, GitHub Action Integration, Output Formats and Policy Configuration

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Prerequisites

Continue reading this section for the full explanation and source context.

Section Running the CLI

Continue reading this section for the full explanation and source context.

Section Global Options

Continue reading this section for the full explanation and source context.

Related topics: Installation and Quick Start, GitHub Action Integration, Output Formats and Policy Configuration

CLI Reference

The decoy-scan CLI is the primary interface for scanning MCP (Model Context Protocol) client configurations and servers for security vulnerabilities. Built as a zero-dependency Node.js application, it provides comprehensive security scanning without requiring installation or configuration.

Overview

The CLI serves as an MCP supply chain security scanner that discovers MCP server configurations, probes running servers, and analyzes them for security risks including tool poisoning, sensitive environment variable exposure, and production readiness issues.

Key capabilities:

  • Scans 7 MCP host configurations (Claude Desktop, Cursor, Windsurf, VS Code, Claude Code, Zed, Cline)
  • Classifies tools by risk level (critical/high/medium/low)
  • Detects 37 prompt injection patterns across 20 attack categories
  • Outputs structured formats for CI/CD integration (JSON, SARIF)
  • Maps findings to OWASP Agentic Top 10

Sources: README.md

Installation & Requirements

Prerequisites

  • Node.js >= 18
  • No npm packages required (zero dependencies)

Running the CLI

npx decoy-scan                        # full scan
npx decoy-scan --json                 # machine-readable output
npx decoy-scan --sarif                # SARIF 2.1.0 for CI/CD

No installation step required. The CLI runs directly via npx.

Sources: AGENTS.md

Command Syntax

decoy-scan [command] [options]

Global Options

OptionAliasDescription
--verbose-vShow all tools including low-risk
--quiet-qSuppress status output
--version-VPrint version
--help-hPrint help

Sources: AGENTS.md

Scan Command

The default command that discovers MCP servers, probes them, and analyzes for security issues.

Scan Options

OptionDescription
--jsonOutput results as JSON
--sarifOutput results as SARIF 2.1.0
--briefOutput minimal summary (implies --json)
--verbose, -vShow all tools including low-risk
--quiet, -qSuppress status output
--no-probeSkip server probing (config-only scan)
--no-advisoriesSkip supply chain advisory checks
--skillsEnable skill scanning
--reportUpload results to Decoy Guard dashboard
--no-telemetryDisable telemetry collection
--verifyAI-verify findings (requires token)

Sources: README.md

Example Usage

# Full scan with pretty output
decoy-scan

# JSON output for scripting
decoy-scan --json

# SARIF output for GitHub Security tab
decoy-scan --sarif

# Config-only scan (no server probing)
decoy-scan --no-probe

# Skip network calls (faster, local only)
decoy-scan --no-advisories

# Verbose mode showing all tools
decoy-scan --verbose

Sources: CONTRIBUTING.md

Explain Subcommand

Resolves what a scan finding means without parsing the full scan output. Useful when an agent sees a finding and needs structured context to act on it.

decoy-scan explain critical              # severity tier
decoy-scan explain tool-description      # finding category
decoy-scan explain prompt-override       # poisoning type
decoy-scan explain read_file             # tool name (runs real classifier rules)
decoy-scan explain list                  # enumerate all explainable targets
decoy-scan explain <target> --json       # structured output (preferred for agents)

Explain Target Types

KindDescriptionExample
tierSeverity levelscritical, high, medium, low
categoryFinding categoriesenv-exposure, command-analysis
poisoningAttack typesprompt-override, instruction-override
toolTool risk classificationsexecute_command, read_file

Sources: AGENTS.md

JSON Output Schema

{
  "tool": "decoy-scan",
  "version": "0.5.1",
  "target": "critical",
  "result": {
    "kind": "tier",
    "key": "critical",
    "title": "Critical",
    "summary": "Can execute code, modify data, or cause irreversible changes.",
    "body": "...",
    "examples": ["execute_command", "write_file", "..."],
    "advice": "..."
  }
}

For tool results, additional fields include risk, reason, matched (the regex that matched), and note when classification relied on name alone.

Sources: AGENTS.md

Exit Codes

The CLI returns specific exit codes for CI/CD pipeline integration:

Exit CodeMeaning
0No critical or high-risk issues found
1High-risk issues found
2Critical issues, tool poisoning, toxic flows, or policy violation

The exit code is also surfaced as exitCode on --json and --brief output, enabling agents to branch on severity without re-deriving it from summary counts.

Sources: AGENTS.md

Output Formats

Pretty Output

Default terminal output with color-coded severity badges:

✗ server-name N critical
! server-name poisoned tool (magenta)
? server-name probe failed
✓ server-name passed

Severity labels introduce each tool group; Low severity collapses to a count.

Sources: CHANGELOG.md

JSON Output Schema

{
  "timestamp": "ISO-8601",
  "hosts": ["Claude Desktop", "Cursor"],
  "servers": [{
    "name": "server-name",
    "hosts": ["Claude Desktop"],
    "command": "npx",
    "args": ["@modelcontextprotocol/server-filesystem"],
    "tools": [{
      "name": "read_file",
      "description": "...",
      "risk": "high",
      "poisoning": [{ "type": "...", "severity": "...", "description": "..." }]
    }],
    "risk": "high",
    "error": null,
    "findings": [{
      "type": "env-exposure",
      "severity": "high",
      "description": "...",
      "source": "env-config"
    }]
  }],
  "summary": {
    "total": 2,
    "critical": 1,
    "high": 1,
    "medium": 0,
    "low": 0,
    "poisoned": 0
  },
  "exitCode": 2
}

Sources: AGENTS.md

SARIF Output

SARIF 2.1.0 format for integration with GitHub Security tab:

decoy-scan --sarif

The SARIF output includes all findings, rules, and tool information compatible with GitHub's code scanning API.

Sources: README.md

Brief Output

Minimal summary object (implies --json):

{
  "servers": 3,
  "critical": 1,
  "high": 2,
  "medium": 4,
  "low": 5,
  "poisoned": 0,
  "status": "fail",
  "exitCode": 2
}

Fields:

  • servers — number of non-decoy, non-error servers scanned
  • critical, high, medium, low — tool risk counts
  • poisoned — number of tool poisoning findings
  • status"pass" (clean), "warn" (high-risk), or "fail" (critical/poisoned/toxic flows)
  • exitCode — matches process exit code

Sources: AGENTS.md

Environment Variables

VariableDescription
DECOY_TOKENAPI token for dashboard upload
DECOY_TELEMETRY=0Disable telemetry collection

Sources: CHANGELOG.md

GitHub Action Integration

The CLI integrates with GitHub Actions via the official action:

# .github/workflows/mcp-security.yml
name: MCP Security
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: decoy-run/decoy-scan@v1
        with:
          policy: no-critical,no-poisoning,no-toxic-flows
          sarif: true
          report: true
          token: ${{ secrets.DECOY_TOKEN }}

Action Inputs

InputDefaultDescription
policyno-critical,no-poisoningComma-separated policy rules
sariftrueUpload SARIF to GitHub Security tab
reportfalseUpload to Decoy Guard dashboard
tokenDecoy API token (for report)
verbosefalseShow all tools including low-risk

Policy Rules

no-critical          Fail on critical tools (code exec, file write)
no-high              Fail on high-risk tools (file read, network)
no-poisoning         Fail on prompt injection in tool descriptions
no-toxic-flows       Fail on cross-server data leak / destructive chains
no-secrets           Fail on secrets exposed in MCP config
require-tripwires    Fail if decoy-tripwire not installed
max-critical=N       Fail if more than N critical tools found

Sources: README.md

Scan Architecture

graph TD
    A[decoy-scan CLI] --> B[Discover MCP Configs]
    B --> C{Host Configs}
    C -->|Claude Desktop| D[~/.claude...json]
    C -->|Cursor| E[~/.cursor...json]
    C -->|VS Code| F[.vscode/mcp.json]
    C -->|Zed| G[~/.config/zed...]
    C -->|Cline| H[~/.cline...]
    
    D --> I[Parse Server Configs]
    E --> I
    F --> I
    G --> I
    H --> I
    
    I --> J[For Each Server]
    J --> K[Probe Server via stdio]
    K --> L{Probe Success?}
    L -->|No| M[Log Error & Continue]
    L -->|Yes| N[Analyze Tool List]
    
    N --> O[Tool Risk Classification]
    N --> P[Poisoning Detection]
    N --> Q[Command Analysis]
    N --> R[Env Exposure Check]
    
    O --> S[Aggregate Findings]
    P --> S
    Q --> S
    R --> S
    
    S --> T{Output Format}
    T -->|Pretty| U[Terminal Output]
    T -->|JSON| V[JSON to stdout]
    T -->|SARIF| W[SARIF to stdout]
    
    M --> X[Final Summary]
    U --> X
    V --> X
    W --> X
    X --> Y[Exit Code 0/1/2]

Development

For local development and testing:

git clone https://github.com/decoy-run/decoy-scan
cd decoy-scan
node bin/cli.mjs --help

No build step required. No dependencies to install.

Manual Testing Modes

node bin/cli.mjs --no-probe              # Config-only
node bin/cli.mjs --no-advisories         # Skip network calls
node bin/cli.mjs --json                  # Verify JSON structure
node bin/cli.mjs --sarif                 # Verify SARIF structure
node bin/cli.mjs --verbose               # Show everything

Running Tests

npm test

This runs 48 tests covering CLI output, JSON/SARIF structure, policy gates, toxic flow detection, skill analysis, and manifest hashing.

Sources: CONTRIBUTING.md

Supported Hosts

The CLI automatically discovers MCP configurations across multiple platforms:

HostmacOS PathWindows PathLinux Path
Claude Desktop~/Library/Application Support/Claude%APPDATA%/Claude~/.config/Claude
Cursor~/.cursor%APPDATA%/Cursor~/.cursor
Windsurf~/.windsurf%APPDATA%/Windsurf~/.windsurf
VS Code.vscode/mcp.json (workspace).vscode/mcp.json.vscode/mcp.json
Claude Code~/.claude.json%APPDATA%/claude.json~/.claude.json
Zed~/.config/zed%APPDATA%/Zed~/.config/zed
Cline~/.cline%APPDATA%/cline~/.cline

Config paths are platform-aware and detected automatically.

Sources: AGENTS.md

Scan Categories

CheckWhat it finds
Tool risk classificationCritical/high/medium/low tools by name + description
Prompt injection detection37 patterns across 20 attack categories in tool descriptions
Toxic flow analysisCross-server data leak (TF001) and destructive (TF002) attack chains
Tool manifest hashingTool additions, removals, and description changes between scans
Skill scanningPrompt injection, hardcoded secrets, suspicious URLs in Claude Code skills
Server command analysisPipe-to-shell, inline code, typosquatting, temp directory spawning
Environment variable exposureAPI keys, tokens, secrets, cloud credentials passed to servers
Supply chain advisories40+ known vulnerable MCP packages via Decoy advisory database
Transport securityHTTP without TLS, missing auth, wildcard CORS, public-bound SSE
Input sanitizationUnconstrained parameters, missing maxLength, open schemas
Permission scopeOver-privileged servers, dangerous capability combinations
OWASP mappingEvery finding mapped to ASI01–ASI05

Sources: README.md

Sources: README.md

GitHub Action Integration

Related topics: CLI Reference, Output Formats and Policy Configuration

Section Related Pages

Continue reading this section for the full explanation and source context.

Section How SARIF Works

Continue reading this section for the full explanation and source context.

Section Manual SARIF Upload

Continue reading this section for the full explanation and source context.

Section Report to Decoy Dashboard

Continue reading this section for the full explanation and source context.

Related topics: CLI Reference, Output Formats and Policy Configuration

GitHub Action Integration

Overview

The decoy-scan GitHub Action provides automated MCP (Model Context Protocol) security scanning as part of a CI/CD pipeline. It integrates directly with GitHub's security infrastructure, enabling teams to enforce security policies on every push and pull request without manual intervention.

The action discovers MCP server configurations across multiple hosts (Claude Desktop, Cursor, Windsurf, VS Code, Claude Code, Zed, and Cline), executes the security scanner, and uploads results to the GitHub Security tab via SARIF format.

Sources: README.md:72-89

Architecture

graph TD
    A[GitHub Workflow Trigger] --> B[decoy-run/decoy-scan Action]
    B --> C[Discover MCP Configs]
    B --> D[CLI: npx decoy-scan]
    D --> E[Scan MCP Servers]
    D --> F[Policy Gate Check]
    E --> G{Policy Violated?}
    F --> G
    G -->|No| H[Exit Code 0]
    G -->|Yes| I[Exit Code 1/2]
    E --> J[Generate SARIF Output]
    J --> K[github/codeql-action/upload-sarif]
    K --> L[GitHub Security Tab]
    I --> M[Fail Build]

The action consists of two primary steps: a scan step that executes the decoy-scan CLI and a SARIF upload step that publishes results to GitHub Security.

Sources: action.yml:20-45

Action Inputs

InputDefaultRequiredDescription
policyno-critical,no-poisoningNoComma-separated policy rules that determine build failure conditions
sariftrueNoWhether to upload SARIF results to GitHub Security tab
reportfalseNoWhether to upload results to Decoy Guard dashboard
tokenConditionalDecoy API token required when report is true
verbosefalseNoShow all tools including low-risk items in output

Sources: README.md:80-86

Workflow Example

name: MCP Security
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: decoy-run/decoy-scan@v1

This minimal configuration scans MCP servers on every push and pull request, uploading SARIF results to the GitHub Security tab.

Sources: README.md:72-89

Policy Rules

The policy input accepts comma-separated rules that define build failure conditions:

RuleBehavior
no-criticalFail on critical tools (code exec, file write)
no-highFail on high-risk tools (file read, network)
no-poisoningFail on prompt injection in tool descriptions
no-toxic-flowsFail on cross-server data leak / destructive chains
no-secretsFail on secrets exposed in MCP config
require-tripwiresFail if decoy-tripwire not installed
max-critical=NFail if more than N critical tools
max-high=NFail if more than N high-risk tools

Sources: README.md:97-106

Exit Codes

CodeMeaning
0No critical or high-risk issues
1High-risk issues found
2Critical issues, tool poisoning, toxic flows, or policy violation

The exit code determines whether the GitHub Actions job succeeds or fails, enabling automatic policy enforcement.

Sources: README.md:43-48

SARIF Integration

How SARIF Works

SARIF (Static Analysis Results Interchange Format) is an industry-standard format for sharing static analysis results. The action generates SARIF 2.1.0 output that GitHub's code scanning feature can ingest and display.

graph LR
    A[decoy-scan CLI] -->|--sarif flag| B[SARIF 2.1.0 JSON]
    B --> C[github/codeql-action/upload-sarif]
    C --> D[GitHub Security Tab]
    C -->|continue-on-error: true| E[Non-blocking Upload]

The action includes SARIF upload as a separate step with continue-on-error: true, ensuring that SARIF upload failures do not cause the workflow to fail when the scan itself passes.

Sources: action.yml:35-44

Manual SARIF Upload

For workflows requiring more control, you can run the scan manually and upload SARIF separately:

- run: npx decoy-scan --sarif > results.sarif
- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: results.sarif

Sources: README.md:108-112

GitHub Step Summary

The action writes a summary to $GITHUB_STEP_SUMMARY providing immediate feedback within the GitHub Actions UI:

graph TD
    A[Scan Complete] --> B{Exit Code}
    B -->|0 - Clean| C["✅ **Clean** — no issues found"]
    B -->|Non-zero| D["🚨 **Issues found** — SUMMARY"]
    B -->|Non-zero| E["Run `npx decoy-scan -v` locally for full details."]

Sources: action.yml:28-34

Permissions

The workflow requires the security-events: write permission to upload SARIF results to the GitHub Security tab:

permissions:
  security-events: write

Sources: README.md:76-78

Advanced Configuration

Report to Decoy Dashboard

To upload results to the Decoy Guard dashboard for centralized monitoring:

- uses: decoy-run/decoy-scan@v1
  with:
    report: true
    token: ${{ secrets.DECOY_TOKEN }}

Verbose Output

To include low-risk tools in the output for full visibility:

- uses: decoy-run/decoy-scan@v1
  with:
    verbose: true

Custom Policy

Combine multiple policy rules for stricter enforcement:

- uses: decoy-run/decoy-scan@v1
  with:
    policy: no-critical,no-poisoning,no-toxic-flows,max-critical=0

Sources: README.md:80-90

Dependencies

The decoy-scan action itself has zero dependencies at runtime. It uses Node.js built-in modules only, following the project's design principle of keeping the tool dependency-free.

The CLI is invoked via npx decoy-scan, which downloads and executes the package on-demand.

Sources: CONTRIBUTING.md:9-10

Version Pinning

For production CI/CD pipelines, pin to a major version to receive minor updates automatically:

- uses: decoy-run/decoy-scan@v1

Or pin to a specific version for complete stability:

- uses: decoy-run/[email protected]

Sources: README.md:24-26

Sources: README.md:72-89

Output Formats and Policy Configuration

Related topics: CLI Reference, GitHub Action Integration, Security Checks and Detection

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Format Types

Continue reading this section for the full explanation and source context.

Section Full Scan Schema

Continue reading this section for the full explanation and source context.

Section Brief Output Schema

Continue reading this section for the full explanation and source context.

Related topics: CLI Reference, GitHub Action Integration, Security Checks and Detection

Output Formats and Policy Configuration

Overview

decoy-scan provides multiple output formats to serve different use cases—from human-readable console output for developers to machine-parseable JSON and SARIF formats for CI/CD pipelines and security automation. The tool also supports a flexible policy configuration system that enables automated enforcement of security rules.

The output and policy system is designed with an "agent-first" philosophy: JSON and SARIF outputs are structurally complete, include exit codes for programmatic branching, and contain all metadata needed for downstream processing without requiring additional parsing or context.

Sources: AGENTS.md:1-20

Output Format Architecture

Format Types

decoy-scan supports four distinct output formats:

FormatFlagPrimary Use CaseExit Code Included
Pretty ConsoleDefaultInteractive terminal inspectionNo
JSON--jsonScripted processing, APIsYes
SARIF 2.1.0--sarifGitHub Security tab, CI toolsYes
Brief--briefQuick summary for automationYes

All structured formats (JSON, SARIF, Brief) include an exitCode field that mirrors the process exit code, enabling agents to branch on results without re-deriving severity from summary counts.

Sources: AGENTS.md:80-95

graph TD
    A[decoy-scan invocation] --> B{CLI Args?}
    B -->|Default| C[Pretty Console Output]
    B -->|--json| D[JSON Output]
    B -->|--sarif| E[SARIF 2.1.0 Output]
    B -->|--brief| F[Brief Summary JSON]
    B -->|combine| G[Multiple Formats]
    C --> H[Terminal Display]
    D --> I[Machine Processing]
    E --> J[GitHub Security Tab]
    F --> K[Quick Status Checks]

JSON Output Format

Full Scan Schema

The JSON output provides complete scan results including all findings, server details, and summary statistics.

{
  "timestamp": "ISO-8601",
  "hosts": ["Claude Desktop", "Cursor"],
  "servers": [{
    "name": "server-name",
    "hosts": ["Claude Desktop"],
    "command": "npx",
    "args": ["@modelcontextprotocol/server-filesystem"],
    "tools": [{
      "name": "read_file",
      "description": "...",
      "risk": "high",
      "poisoning": [{ "type": "...", "severity": "...", "description": "..." }]
    }],
    "risk": "high",
    "error": null,
    "findings": [{
      "type": "env-exposure",
      "severity": "high",
      "description": "...",
      "source": "env-config"
    }]
  }],
  "summary": {
    "total": 2,
    "critical": 1,
    "high": 2,
    "medium": 4,
    "low": 5,
    "poisoned": 0
  },
  "exitCode": 1
}

Sources: AGENTS.md:28-55

Brief Output Schema

The --brief format provides a minimal summary object optimized for quick status checks:

{
  "servers": 3,
  "critical": 1,
  "high": 2,
  "medium": 4,
  "low": 5,
  "poisoned": 0,
  "status": "fail",
  "exitCode": 2
}
FieldTypeDescription
serversnumberNon-decoy, non-error servers scanned
criticalnumberCritical severity tool count
highnumberHigh severity tool count
mediumnumberMedium severity tool count
lownumberLow severity tool count
poisonednumberPrompt injection findings
statusstring"pass", "warn", or "fail"
exitCodenumberProcess exit code (0/1/2)

Sources: AGENTS.md:60-75

SARIF 2.1.0 Output

SARIF (Static Analysis Results Interchange Format) is generated by the toSarif() function in lib/sarif.mjs. This format is specifically designed for integration with GitHub Security tab and other security scanning platforms.

Key Features

  • Rule definitions mapping to OWASP Agentic Top 10 categories (ASI01–ASI05)
  • Result categorization by severity level
  • Tool metadata including version and run timestamps
  • Multi-host support in result locations

CLI Integration

When using the GitHub Action or CLI with SARIF output:

node bin/cli.mjs --sarif --no-advisories > scan-results.sarif

The SARIF file can then be uploaded using the GitHub CodeQL action:

- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: ${{ steps.scan.outputs.sarif-file }}
    category: decoy-scan

Sources: action.yml:40-45

SARIF Structure Overview

graph TD
    A[SARIF 2.1.0 Log] --> B[runs array]
    B --> C[Tool driver]
    B --> D[Results array]
    B --> E[Rules definitions]
    D --> F[Individual findings]
    E --> G[ASI01-ASI05 mappings]
    F --> H[severity, message, locations]

Policy Configuration System

Policy Rules

The policy system uses comma-separated rules to define pass/fail criteria:

RuleEffectExample
no-criticalFail on critical tools (code exec, file write)policy: no-critical
no-highFail on high-risk tools (file read, network)policy: no-high
no-poisoningFail on prompt injection in tool descriptionspolicy: no-poisoning
no-toxic-flowsFail on cross-server data leak/destructive chainspolicy: no-toxic-flows
no-secretsFail on secrets exposed in MCP configpolicy: no-secrets
require-tripwiresFail if decoy-tripwire not installedpolicy: require-tripwires
max-critical=NFail if critical tools exceed Npolicy: max-critical=0

Multiple rules can be combined: policy: no-critical,no-poisoning,no-toxic-flows

Sources: README.md:80-90

Policy Gates

The analyzePolicyGates() function evaluates scan results against configured policy rules. Each finding type maps to one or more policy rules:

Finding TypeMaps to Policy Rules
Critical risk toolsno-critical, max-critical=N
High risk toolsno-high
Prompt injectionno-poisoning
Toxic flows (TF001, TF002)no-toxic-flows
Environment exposureno-secrets
Missing decoy-tripwirerequire-tripwires

Sources: index.mjs:RISK_PATTERNS,POISONING_PATTERNS

Exit Codes

The exit code system provides programmatic feedback about scan results:

CodeMeaningTriggers
0No critical or high-risk issuesClean scan
1High-risk issues foundHigh-severity tools present
2Critical issues, tool poisoning, toxic flows, or policy violationCritical tools, injection detected, or policy failure

Exit codes are included in both --json and --brief output as the exitCode field, enabling conditional logic in scripts:

const result = JSON.parse(childProcess.execSync('decoy-scan --json'));
if (result.exitCode === 2) {
  process.exit(1); // Block deployment
}

Sources: AGENTS.md:75-82

Explain Subcommand

The explain subcommand provides structured explanations for severity tiers, finding categories, poisoning types, and tool names:

decoy-scan explain critical              # severity tier
decoy-scan explain tool-description     # finding category
decoy-scan explain prompt-override      # poisoning type
decoy-scan explain read_file           # tool name (runs real classifier)
decoy-scan explain list                 # enumerate all explainable targets
decoy-scan explain <target> --json      # structured output

Explain Output Schema

{
  "tool": "decoy-scan",
  "version": "0.5.1",
  "target": "critical",
  "result": {
    "kind": "tier",
    "key": "critical",
    "title": "Critical",
    "summary": "Can execute code, modify data, or cause irreversible changes.",
    "body": "Detailed explanation...",
    "examples": ["execute_command", "write_file", "..."],
    "advice": "Remediation guidance..."
  }
}
result.kindDescription
tierSeverity level (critical, high, medium, low)
categoryFinding category (env-exposure, missing-schema, etc.)
poisoningPoisoning type (instruction-override, credential-harvesting, etc.)
toolTool name classification with risk level and matched pattern

Sources: AGENTS.md:32-55

CLI Options Reference

OptionShortDescription
--jsonJSON output format
--sarifSARIF 2.1.0 output format
--briefBrief summary (implies --json)
--verbose-vShow all tools including low-risk
--quiet-qSuppress status output
--no-probeConfig-only scan, skip server probing
--no-advisoriesSkip network calls to advisory database
--no-telemetryOpt out of telemetry
--policyComma-separated policy rules
--reportUpload results to Decoy Guard dashboard
--version-VPrint version
--help-hPrint help

Sources: AGENTS.md:15-30

Integration Patterns

CI/CD Pipeline

graph LR
    A[Push/PR] --> B[Checkout]
    B --> C[decoy-scan Action]
    C --> D{Policy Pass?}
    D -->|Yes| E[Continue Build]
    D -->|No| F[Fail Build]
    C --> G[Upload SARIF]
    G --> H[GitHub Security Tab]

Agentic Workflow

graph TD
    A[Agent receives scan result] --> B{exitCode === 0?}
    B -->|Yes| C[Proceed]
    B -->|No| D{exitCode === 2?}
    D -->|Yes| E[Block - Critical/Poisoning]
    D -->|No| F{exitCode === 1?}
    F -->|Yes| G[Warn - High-risk]
    F -->|No| H[Unknown state]
    B -->|Parse| I[Tool analysis]
    I --> J[Explain each finding]
    J --> K[Remediation]

Output Stability Guarantees

decoy-scan maintains backward compatibility for structured outputs:

  1. JSON Schema Versioning — The version field in explain output enables consumers to handle schema changes
  2. Exit Code Stability — Exit code meanings are documented and stable across versions
  3. SARIF Compliance — SARIF output adheres to OASIS SARIF 2.1.0 specification

These guarantees enable reliable automation without constant schema adaptation.

Sources: AGENTS.md:1-20

Doramagic Pitfall Log

Source-linked risks stay visible on the manual page so the preview does not read like a recommendation.

medium README/documentation is current enough for a first validation pass.

The project should not be treated as fully validated until this signal is reviewed.

medium Maintainer activity is unknown

Users cannot judge support quality until recent activity, releases, and issue response are checked.

medium no_demo

The project may affect permissions, credentials, data exposure, or host boundaries.

medium no_demo

The project may affect permissions, credentials, data exposure, or host boundaries.

Doramagic Pitfall Log

Doramagic extracted 7 source-linked risk signals. Review them before installing or handing real data to the project.

1. Capability assumption: README/documentation is current enough for a first validation pass.

  • Severity: medium
  • Finding: README/documentation is current enough for a first validation pass.
  • User impact: The project should not be treated as fully validated until this signal is reviewed.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: capability.assumptions | github_repo:1185640470 | https://github.com/decoy-run/decoy-scan | README/documentation is current enough for a first validation pass.

2. Maintenance risk: Maintainer activity is unknown

  • Severity: medium
  • Finding: Maintenance risk is backed by a source signal: Maintainer activity is unknown. Treat it as a review item until the current version is checked.
  • User impact: Users cannot judge support quality until recent activity, releases, and issue response are checked.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: evidence.maintainer_signals | github_repo:1185640470 | https://github.com/decoy-run/decoy-scan | last_activity_observed missing

3. Security or permission risk: no_demo

  • Severity: medium
  • Finding: no_demo
  • User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: downstream_validation.risk_items | github_repo:1185640470 | https://github.com/decoy-run/decoy-scan | no_demo; severity=medium

4. Security or permission risk: no_demo

  • Severity: medium
  • Finding: no_demo
  • User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: risks.scoring_risks | github_repo:1185640470 | https://github.com/decoy-run/decoy-scan | no_demo; severity=medium

5. Security or permission risk: Decoy Scan - MCP Security for CI/CD

  • Severity: medium
  • Finding: Security or permission risk is backed by a source signal: Decoy Scan - MCP Security for CI/CD. Treat it as a review item until the current version is checked.
  • User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: Source-linked evidence: https://github.com/decoy-run/decoy-scan/releases/tag/v1

6. Maintenance risk: issue_or_pr_quality=unknown

  • Severity: low
  • Finding: issue_or_pr_quality=unknown。
  • User impact: Users cannot judge support quality until recent activity, releases, and issue response are checked.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: evidence.maintainer_signals | github_repo:1185640470 | https://github.com/decoy-run/decoy-scan | issue_or_pr_quality=unknown

7. Maintenance risk: release_recency=unknown

  • Severity: low
  • Finding: release_recency=unknown。
  • User impact: Users cannot judge support quality until recent activity, releases, and issue response are checked.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: evidence.maintainer_signals | github_repo:1185640470 | https://github.com/decoy-run/decoy-scan | release_recency=unknown

Source: Doramagic discovery, validation, and Project Pack records

Community Discussion Evidence

These external discussion links are review inputs, not standalone proof that the project is production-ready.

Sources 2

Count of project-level external discussion links exposed on this manual page.

Use Review before install

Open the linked issues or discussions before treating the pack as ready for your environment.

Community Discussion Evidence

Doramagic exposes project-level community discussion separately from official documentation. Review these links before using decoy-scan with real data or production workflows.

Source: Project Pack community evidence and pitfall evidence