What Are MCP Least Privilege Violations and How SkillSpector Detects Them

MCP least privilege violations happen when a skill's declared permissions in its SKILL.md manifest do not precisely match the capabilities—such as network access, file operations, or shell execution—actually present in its code, and SkillSpector detects these mismatches through four specific rule families (LP1–LP4) that analyze the gap between manifest declarations and runtime behavior.

NVIDIA SkillSpector enforces least privilege security for MCP-enabled skills by comparing the permissions list defined in a skill's manifest against the capabilities detected in its executable source files. The analyzer implements a bidirectional check that flags both under-privileged code (missing declarations) and over-privileged manifests (excessive declarations), ensuring that skills request exactly the access they need and no more.

Understanding the Four Rule Families

SkillSpector's MCP Least-Privilege analyzer (src/skillspector/nodes/analyzers/mcp_least_privilege.py) categorizes violations into four distinct rule families, each with specific severity and confidence thresholds:

  • LP1 – Under-Declared Capability (HIGH severity): A capability is detected in the code (e.g., subprocess calls, httpx imports, or open() statements) but has no corresponding entry in the SKILL.md permissions field. Confidence is 0.75 for production code or 0.55 if the capability appears only in test files.

  • LP2 – Wildcard Permission (MEDIUM severity): The manifest contains overly broad permissions such as *, all, full, or any. These grant blanket access and violate the principle of least privilege with confidence ≥ 0.90.

  • LP3 – No Permissions Declared (MEDIUM severity): The permissions field is missing, null, or empty, yet the analyzer detects executable capabilities in the skill's code. This triggers with confidence ≥ 0.70.

  • LP4 – Over-Declared Permission (LOW severity): A permission is listed in the manifest but no corresponding capability exists in the code (e.g., declaring write permission while never opening a file for writing). Confidence is ≥ 0.65.

How the Detection Engine Works

The analyzer operates in src/skillspector/nodes/analyzers/mcp_least_privilege.py by executing a ten-step workflow that inspects both static metadata and source code:

  1. Early Exit: Skips analysis if the skill lacks a manifest or contains no executable files (documentation-only skills).

  2. Manifest Ingestion: Reads manifest.get("permissions"), handling None, empty lists, or string arrays.

  3. File Collection: Gathers executable files from component_metadata and loads their content via file_cache.

  4. Capability Detection: Uses _detect_capabilities(content) with regex patterns defined in _CAPABILITY_PATTERNS to identify imports like subprocess (mapped to shell), httpx (mapped to network), and open(..., "r") (mapped to file_read).

  5. Permission Mapping: Normalizes declared permissions to capability categories via _map_permissions_to_categories(permissions), using the case-insensitive _PERM_TO_CAPABILITY dictionary.

  6. Rule Evaluation: Applies LP2 (wildcard check), LP3 (empty permissions check), LP1 (uncovered capabilities), and LP4 (unused declarations) sequentially.

  7. Finding Generation: Emits structured Finding objects containing rule IDs, severity levels, confidence scores, and remediation advice.

Code Examples of Violation Types

Under-Declared Capabilities (LP1)

When code uses httpx and subprocess but the manifest omits the matching permissions, SkillSpector generates an LP1 finding with HIGH severity:


# scripts/agent.py

import httpx          # network capability

import subprocess    # shell capability

# SKILL.md

---
name: underdeclared-skill

# permissions: []  # Missing network and shell

triggers: []
---

The analyzer outputs:

{
  "rule_id": "LP1",
  "severity": "HIGH",
  "confidence": 0.75,
  "message": "Code capability 'network' detected in scripts/agent.py but not covered by declared permissions."
}

As implemented in tests/test_mcp_least_privilege.py, capabilities found only in files matching test_*.py or *_test.py patterns receive reduced confidence (0.55) because they likely represent test infrastructure rather than production behavior.

Wildcard Permissions (LP2)

Manifests containing glob-style permissions trigger LP2:


# SKILL.md

---
name: overprivileged-skill
permissions: ["*"]
triggers: []
---

Result:

{
  "rule_id": "LP2",
  "severity": "MEDIUM",
  "confidence": 0.90,
  "message": "Permission list contains a wildcard entry ('*', 'all', 'full', or 'any'), granting blanket access ..."
}

Missing Permission Blocks (LP3)

When a manifest completely lacks a permissions field despite containing executable code, the analyzer emits LP3:

{
  "rule_id": "LP3",
  "severity": "MEDIUM",
  "confidence": 0.70,
  "message": "Skill has no declared permissions but code capabilities were detected: network, shell."
}

Over-Declared Permissions (LP4)

Declaring permissions that never appear in code results in LOW severity findings:


# SKILL.md

permissions: ["bash", "network", "write"]

# scripts/helper.py

import httpx  # Only network is used

Output:

{
  "rule_id": "LP4",
  "severity": "LOW",
  "confidence": 0.65,
  "message": "Permission 'write' is declared but no corresponding code capability (file_write) was detected."
}

Confidence Scoring and Normalization

The analyzer employs case-insensitive matching for permission names, so declaring ["BASH", "Network"] correctly maps to shell and network categories without triggering LP1 false positives. The _map_permissions_to_categories function normalizes inputs before comparison, ensuring that capitalization differences between manifest declarations and internal capability tags do not produce violations.

Summary

  • MCP least privilege violations represent mismatches between a skill's declared permissions and its actual code capabilities.
  • SkillSpector detects these via src/skillspector/nodes/analyzers/mcp_least_privilege.py using four rule families: LP1 (under-declared), LP2 (wildcard), LP3 (no permissions), and LP4 (over-declared).
  • Regex-based detection in _detect_capabilities identifies concrete capabilities like network, shell, and file operations.
  • Test-only code receives reduced confidence scores (0.55 vs 0.75) to minimize false positives in development utilities.
  • Remediation requires aligning the SKILL.md permissions list exactly with the capabilities present in production source files.

Frequently Asked Questions

What is the difference between LP1 and LP4 violations?

LP1 (Under-Declared) fires when code contains capabilities not listed in the manifest, representing a security risk where the skill might lack necessary sandbox restrictions. LP4 (Over-Declared) fires when the manifest lists permissions that the code never uses, representing unnecessary privilege grants that could be exploited if the code changes. LP1 carries HIGH severity while LP4 carries LOW severity.

How does SkillSpector distinguish between production and test code?

The analyzer checks file paths against patterns test_*.py and *_test.py in src/skillspector/nodes/analyzers/mcp_least_privilege.py. Capabilities found exclusively in these files trigger LP1 with a reduced confidence of 0.55 rather than the standard 0.75, reflecting the lower risk associated with test-only functionality.

Why are wildcard permissions considered a violation?

Wildcard entries like * or all in the permissions field violate the principle of least privilege by granting blanket access to all capabilities. The analyzer detects these via LP2 with ≥ 0.90 confidence because they eliminate the security boundary between the skill and the host system, contradicting the explicit permission model required by the MCP specification.

Where is the MCP least privilege detection logic implemented?

The core detection engine resides in src/skillspector/nodes/analyzers/mcp_least_privilege.py within the NVIDIA/SkillSpector repository. This file contains the _CAPABILITY_PATTERNS regex definitions, _detect_capabilities extraction logic, and the rule families LP1–LP4 that generate findings. Comprehensive unit tests validating each rule are located in tests/test_mcp_least_privilege.py.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →