# How the MCP Least Privilege Analyzer Verifies Capability Declarations in SkillSpector

> Discover how the MCP least privilege analyzer verifies capability declarations in SkillSpector by comparing SKILL.md permissions against actual code capabilities using regex.

- Repository: [NVIDIA Corporation/SkillSpector](https://github.com/NVIDIA/SkillSpector)
- Tags: deep-dive
- Published: 2026-06-24

---

**The MCP least privilege analyzer verifies capability declarations by comparing the permissions listed in a skill's [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md) manifest against the actual capabilities detected in the source code through regex pattern matching.**

The NVIDIA SkillSpector repository includes a static analysis tool that ensures skill manifests accurately reflect security-relevant code behavior. The analyzer enforces four specific LP (Least Privilege) rules by cross-referencing declared permissions against detected capabilities, generating structured findings when mismatches occur.

## Processing Skill Manifests and Source Code

The analyzer begins by ingesting the skill's state, which contains both the declared permissions and the actual source code files.

### Loading the Manifest and File Cache

In [`src/skillspector/nodes/analyzers/mcp_least_privilege.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/mcp_least_privilege.py), the `node` function receives a `SkillspectorState` object containing the skill manifest and a cache of executable files. Lines 66-70 extract these components:

```python
manifest = state.get("manifest") or {}
file_cache = state.get("file_cache") or {}

```

The `file_cache` maps file paths to their source content, enabling the analyzer to inspect every executable file without redundant disk I/O.

### Detecting Capabilities with Regex Patterns

For each file in the cache, the analyzer calls `_detect_capabilities` (lines 27-35) to scan the source text against a table of regex patterns defined in `_CAPABILITY_PATTERNS`:

```python
caps = _detect_capabilities(content)

```

These patterns identify usage across six categories: **shell**, **network**, **file_read**, **file_write**, **env**, and **mcp**. The function returns a mapping of `file_capabilities` holding detected categories per file, while `all_caps` aggregates unique categories across the entire skill.

### Mapping Declared Permissions to Categories

The analyzer normalizes manifest permissions using `_map_permissions_to_categories` (line 64), which converts raw permission strings like `"bash"` or `"network"` into standardized capability categories via the `_PERM_TO_CAPABILITY` lookup table.

## The Four LP Rules for Capability Verification

The core verification logic implements four distinct rules (LP1-LP4) that generate findings based on the comparison between declared and detected capabilities.

### LP2: Flagging Wildcard Permissions (lines 92-132)

If any permission value matches wildcards such as `"*"`, `"all"`, `"full"`, or `"any"` (defined in `_WILDCARD_PERMS`), the analyzer immediately emits a high-severity finding. This prevents overly broad permission declarations that violate the principle of least privilege.

### LP3: Identifying Missing Permission Declarations (lines 135-159)

When the `permissions` key is missing or empty in the manifest, yet the capability detection found security-relevant code patterns, the analyzer generates an LP3 finding. This catches skills that use capabilities like `subprocess.Popen` without explicitly declaring them in [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md).

### LP1: Detecting Under-Declared Capabilities (lines 162-204)

For each capability detected in the code that is not covered by the declared categories, the analyzer produces an LP1 finding with high severity. The confidence score varies based on context: capabilities found in test files receive a confidence of 0.55, while production code receives 0.75. All confidence values are clamped to the [0, 1] range using the `_clamp` helper.

### LP4: Reporting Over-Declared Permissions (lines 207-254)

When the manifest declares permissions that map to capability categories not detected in the code, the analyzer generates a low-severity LP4 finding. This identifies stale or unnecessary permissions that should be removed from the manifest to maintain accuracy.

## Practical Examples of Capability Verification

The following scenarios demonstrate how the analyzer processes real-world skill configurations.

### Example 1: Missing Permissions Declaration

Consider a [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md) that omits the `permissions` field entirely:

```yaml

# SKILL.md

name: greet
description: Says hello

```

If the skill contains `subprocess.Popen` in its source, running the MCP scan produces an LP3 finding:

```python
from skillspector.mcp_server import run_scan

result = await run_scan(
    target="/path/to/greet_skill",
    use_llm=False,
    output_format="json",
)
print(result["findings"])

# → [{'rule_id': 'LP3', 'message': 'Skill has no declared permissions ...'}]

```

### Example 2: Over-Declared Network Permission

When a skill declares network access but only performs file operations:

```yaml

# SKILL.md

permissions:
  - network   # declared, but code only reads files

```

The analyzer emits an LP4 finding since no network capability patterns were detected:

```json
{
  "rule_id": "LP4",
  "message": "Permission 'network' is declared but no corresponding code capability (network) was detected."
}

```

### Example 3: Under-Declared Shell Capability

If a skill declares only file read permissions but executes shell commands:

```yaml
permissions:
  - file_read

```

The presence of `subprocess.Popen` triggers an LP1 finding for the missing `shell` capability:

```json
{
  "rule_id": "LP1",
  "message": "Code capability 'shell' detected in greet.py but not covered by declared permissions."
}

```

## Summary

- The MCP least privilege analyzer in [`src/skillspector/nodes/analyzers/mcp_least_privilege.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/mcp_least_privilege.py) validates that [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md) manifests accurately reflect code capabilities.
- It uses regex patterns in `_CAPABILITY_PATTERNS` to detect six categories of security-relevant operations across the `file_cache`.
- **LP2** blocks wildcard permissions like `"*"` or `"all"` that grant excessive access.
- **LP3** catches skills using capabilities without any declared permissions list.
- **LP1** identifies under-declared capabilities with higher confidence for production code (0.75) versus test files (0.55).
- **LP4** flags over-declared permissions that have no corresponding code usage.
- Each finding follows the `Finding` model defined in [`src/skillspector/models.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/models.py), containing rule IDs, severity levels, and remediation advice.

## Frequently Asked Questions

### What is the MCP least privilege analyzer?

The MCP least privilege analyzer is a static analysis component in the NVIDIA SkillSpector repository that verifies whether a skill's declared permissions in its [`SKILL.md`](https://github.com/NVIDIA/SkillSpector/blob/main/SKILL.md) manifest match the actual security capabilities used in its source code. It implements four specific rules (LP1-LP4) to enforce the principle of least privilege for MCP (Model Context Protocol) skills.

### How does the analyzer detect capabilities in code?

The analyzer detects capabilities using the `_detect_capabilities` function (lines 27-35 of [`mcp_least_privilege.py`](https://github.com/NVIDIA/SkillSpector/blob/main/mcp_least_privilege.py)), which scans source code against predefined regex patterns in `_CAPABILITY_PATTERNS`. These patterns identify specific imports, function calls, or APIs related to shell execution, network operations, file system access, environment variables, and MCP interactions.

### What is the difference between LP1 and LP4 findings?

**LP1 findings** indicate under-declared capabilities, meaning the code uses a security-sensitive operation (like shell execution) that is not covered by the manifest's permissions. **LP4 findings** indicate over-declared permissions, meaning the manifest lists a capability (like network access) that the code does not actually use. LP1 carries higher severity since it represents a potential security risk, while LP4 represents manifest hygiene issues.

### How does the analyzer handle test files?

The analyzer applies different confidence scores based on file context. When capabilities are detected in test files, the confidence score is reduced to 0.55 compared to 0.75 for production code. This differentiation helps prioritize remediation efforts toward production security risks while still acknowledging test-time capability usage.