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.,
subprocesscalls,httpximports, oropen()statements) but has no corresponding entry in theSKILL.mdpermissionsfield. 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, orany. These grant blanket access and violate the principle of least privilege with confidence ≥ 0.90. -
LP3 – No Permissions Declared (MEDIUM severity): The
permissionsfield 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
writepermission 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:
-
Early Exit: Skips analysis if the skill lacks a manifest or contains no executable files (documentation-only skills).
-
Manifest Ingestion: Reads
manifest.get("permissions"), handlingNone, empty lists, or string arrays. -
File Collection: Gathers executable files from
component_metadataand loads their content viafile_cache. -
Capability Detection: Uses
_detect_capabilities(content)with regex patterns defined in_CAPABILITY_PATTERNSto identify imports likesubprocess(mapped to shell),httpx(mapped to network), andopen(..., "r")(mapped to file_read). -
Permission Mapping: Normalizes declared permissions to capability categories via
_map_permissions_to_categories(permissions), using the case-insensitive_PERM_TO_CAPABILITYdictionary. -
Rule Evaluation: Applies LP2 (wildcard check), LP3 (empty permissions check), LP1 (uncovered capabilities), and LP4 (unused declarations) sequentially.
-
Finding Generation: Emits structured
Findingobjects 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.pyusing four rule families: LP1 (under-declared), LP2 (wildcard), LP3 (no permissions), and LP4 (over-declared). - Regex-based detection in
_detect_capabilitiesidentifies 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.mdpermissionslist 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →