LP1 and LP3 tell the user to add a permissions field to SKILL.md. The Agent Skills spec has no permissions field — following the remediation literally produces frontmatter the spec doesn't define.
The analyzer already knows this. _normalize_allowed_tools / _map_allowed_tools_to_categories exist precisely because allowed-tools is the Agent Skills equivalent, and node() reads both:
# mcp_least_privilege.py:234
# `allowed-tools` (Agent Skills standard) is also a permission declaration.
allowed_tools = _normalize_allowed_tools(manifest.get("allowed-tools"))
Only the user-facing strings are out of step.
Affected
| Location |
Text |
mcp_least_privilege.py:300 (LP3) |
"Add a 'permissions' field to SKILL.md listing the capabilities this skill requires." |
mcp_least_privilege.py:356 (LP1) |
"Add the '{cap}' permission to SKILL.md, or remove the code that requires it." |
docs/B.3.1-mcp-least-privilege.md:123 (LP1) |
"Add the missing permission to SKILL.md, or remove the code" |
docs/B.3.1-mcp-least-privilege.md:174 (LP3) |
"Add a permissions field to SKILL.md listing the capabilities" |
LP2 and LP4 read fine — they talk about permissions generically without naming a field to add.
Why it matters
permissions is correct for an MCP server manifest; allowed-tools is correct for a SKILL.md. Since both flow through the same analyzer, the remediation reads as authoritative for whichever manifest was scanned — and for skills it points at a field that doesn't exist. In our case it sent us toward a spec-invalid edit before we checked the spec.
The spec field is a space-separated string, not a list, which is worth reflecting in any suggested snippet:
allowed-tools: Bash(python:*) Read Write
(The spec marks allowed-tools experimental.)
Suggested fix
Pick the wording from whichever manifest shape was scanned — the analyzer already has manifest in hand, so a permissions-vs-allowed-tools branch on the same signal that drives _map_allowed_tools_to_categories would cover it. Mentioning both fields in one string would also work and is a smaller change.
Happy to send a PR if you'd like — just say which shape you'd prefer.
Context
Found while gating a Rust project's vendored Agent Skills on skillspector scan --no-llm in CI. The LP3 finding itself was accurate and actionable — we filed anthropics/skills#1468 off the back of it. Only the remediation wording sent us the wrong way.
LP1 and LP3 tell the user to add a
permissionsfield toSKILL.md. The Agent Skills spec has nopermissionsfield — following the remediation literally produces frontmatter the spec doesn't define.The analyzer already knows this.
_normalize_allowed_tools/_map_allowed_tools_to_categoriesexist precisely becauseallowed-toolsis the Agent Skills equivalent, andnode()reads both:Only the user-facing strings are out of step.
Affected
mcp_least_privilege.py:300(LP3)"Add a 'permissions' field to SKILL.md listing the capabilities this skill requires."mcp_least_privilege.py:356(LP1)"Add the '{cap}' permission to SKILL.md, or remove the code that requires it."docs/B.3.1-mcp-least-privilege.md:123(LP1)docs/B.3.1-mcp-least-privilege.md:174(LP3)permissionsfield to SKILL.md listing the capabilities"LP2 and LP4 read fine — they talk about permissions generically without naming a field to add.
Why it matters
permissionsis correct for an MCP server manifest;allowed-toolsis correct for aSKILL.md. Since both flow through the same analyzer, the remediation reads as authoritative for whichever manifest was scanned — and for skills it points at a field that doesn't exist. In our case it sent us toward a spec-invalid edit before we checked the spec.The spec field is a space-separated string, not a list, which is worth reflecting in any suggested snippet:
(The spec marks
allowed-toolsexperimental.)Suggested fix
Pick the wording from whichever manifest shape was scanned — the analyzer already has
manifestin hand, so apermissions-vs-allowed-toolsbranch on the same signal that drives_map_allowed_tools_to_categorieswould cover it. Mentioning both fields in one string would also work and is a smaller change.Happy to send a PR if you'd like — just say which shape you'd prefer.
Context
Found while gating a Rust project's vendored Agent Skills on
skillspector scan --no-llmin CI. The LP3 finding itself was accurate and actionable — we filed anthropics/skills#1468 off the back of it. Only the remediation wording sent us the wrong way.