claude-code - 💡(How to fix) Fix [BUG] `Skill()` entries in skill frontmatter `allowed-tools` are ignored — invoking a nested skill prompts for approval despite the parent skill granting arbitrary script execution

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

If Skill() entries are intentionally excluded from allowed-tools (a security-policy decision), the docs at https://code.claude.com/docs/en/skills must state this exception explicitly, and the rationale must be articulated — because excluding Skill() while admitting Bash(arbitrary-script.ts:*) provides no defensive benefit (see the argument under "Additional Information").

Error Messages/Logs

No error message is surfaced; the prompt simply appears for the Skill(commit-style) invocation while every other tool listed in allowed-tools runs without prompting. In auto mode, no prompt is shown.

  • #30949 — [DOCS] Skills docs should document interactive-tool exception to allowed-tools auto-approval behavior (open). The CHANGELOG for 2.1.69 introduced an undocumented exception ("interactive tools should not be silently auto-approved via allowed-tools"). Skill() may be in a similar undocumented-exception category.
  1. If exclusion is intentional, document the exception explicitly at https://code.claude.com/docs/en/skills under the allowed-tools section, list which tool categories are excluded (interactive tools per 2.1.69, Skill(), anything else), and explain the rationale — including why auto mode and default mode diverge.

Root Cause

The non-symmetry has no defensive value. The parent skill in question already auto-approves arbitrary TypeScript execution via Bash(commit-prepare.ts:*). Anything that arbitrary script can do, a nested skill invocation can do — and strictly less, in this case (the child skill is read-only git log). There is no expansion of trust caused by approving the nested skill, so prompting the user to approve only that one entry while silently accepting the broader script-execution grant is a permission UX inconsistency, not a guardrail.

Code Example

(Permission prompt shown to user in default mode)
Use skill "commit-style"?
Claude may use instructions, code, or files from this Skill.
...
Do you want to proceed?
> 1. Yes
  2. Yes, and don't ask again for commit-style in <project>
  3. No, and tell Claude what to do differently (esc)


No error message is surfaced; the prompt simply appears for the `Skill(commit-style)` invocation while every other tool listed in `allowed-tools` runs without prompting. In auto mode, no prompt is shown.

---

allowed-tools: AskUserQuestion, Bash(commit-prepare.ts:*), Bash(editor.ts:*), Bash(git commit:*), Edit, Read, Skill(commit-style)
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • I am using the latest version of Claude Code

What's Wrong?

When a parent skill declares Skill(child-skill) in its frontmatter allowed-tools, invoking the child skill from the parent still triggers a permission prompt asking the user to approve the nested skill invocation. Other entries in the same allowed-tools list (Bash patterns, Read, Edit, AskUserQuestion, etc.) are auto-approved as documented.

This is inconsistent: every non-Skill() entry in allowed-tools is honored, but Skill() entries are silently ignored by the permission check, even though Skill(...) is documented as valid permission syntax for permissions.allow in settings.json.

The non-symmetry has no defensive value. The parent skill in question already auto-approves arbitrary TypeScript execution via Bash(commit-prepare.ts:*). Anything that arbitrary script can do, a nested skill invocation can do — and strictly less, in this case (the child skill is read-only git log). There is no expansion of trust caused by approving the nested skill, so prompting the user to approve only that one entry while silently accepting the broader script-execution grant is a permission UX inconsistency, not a guardrail.

Mode-dependent behavior

The prompt only appears outside of auto mode. In auto mode the nested skill invocation is approved without a prompt; in default mode the prompt appears. This further suggests the issue is a missing path in the default-mode permission resolver rather than an intentional policy: if treating nested skill invocation as security-relevant were the design intent, auto mode's classifier would presumably also gate it.

What Should Happen?

Skill(child-skill) listed in a parent skill's frontmatter allowed-tools should grant nested skill invocation without an additional permission prompt, in the same way that Bash(...), Read, Edit, etc. are granted. The auto-approval scope should be limited to the lifetime of the parent skill, matching the existing semantics for other tool entries. Behavior should be the same regardless of permission mode (auto / default).

If Skill() entries are intentionally excluded from allowed-tools (a security-policy decision), the docs at https://code.claude.com/docs/en/skills must state this exception explicitly, and the rationale must be articulated — because excluding Skill() while admitting Bash(arbitrary-script.ts:*) provides no defensive benefit (see the argument under "Additional Information").

Error Messages/Logs

(Permission prompt shown to user in default mode)
Use skill "commit-style"?
Claude may use instructions, code, or files from this Skill.
...
Do you want to proceed?
> 1. Yes
  2. Yes, and don't ask again for commit-style in <project>
  3. No, and tell Claude what to do differently (esc)


No error message is surfaced; the prompt simply appears for the `Skill(commit-style)` invocation while every other tool listed in `allowed-tools` runs without prompting. In auto mode, no prompt is shown.

Steps to Reproduce

Reproduces with the konoka commit plugin:

Steps:

  1. Install the konoka commit plugin.
  2. Stage any change in a git repository.
  3. Run /commit (or any prompt that triggers the commit skill) outside of auto mode.
  4. Observe:
    • Bash(git commit:*), Edit, Read, AskUserQuestion: all auto-approved (correct — they are listed in allowed-tools)
    • Skill(commit-style): permission prompt appears (incorrect — it is also listed in allowed-tools)
  5. Repeat in auto mode: the Skill(commit-style) prompt does not appear.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

No response

Claude Code Version

2.1.114 (Claude Code)

Platform

Anthropic API

Operating System

Other Linux

Terminal/Shell

Other

Additional Information

Security argument: why Skill() exclusion from allowed-tools provides no defense

The current behavior cannot be justified as a security guardrail. Consider the parent skill's allowed-tools:

allowed-tools: AskUserQuestion, Bash(commit-prepare.ts:*), Bash(editor.ts:*), Bash(git commit:*), Edit, Read, Skill(commit-style)

Bash(commit-prepare.ts:*) grants the parent skill the ability to run an arbitrary TypeScript file. Inside that file, child_process.exec, filesystem writes, network calls, and even spawning claude subprocesses are all reachable. The trust granted to this skill is already maximal in practical terms.

Adding Skill(commit-style) on top of that grants the skill the ability to invoke a child skill that itself only declares Bash(git log:*) and one local script. The set of capabilities Skill(commit-style) adds is a strict subset of what Bash(commit-prepare.ts:*) already permits. Therefore, prompting the user only for the nested skill invocation while silently accepting the broader script execution is a UX inconsistency without security value — comparable to leaving the front door open and asking the user to confirm an open window.

That auto mode does not gate this invocation reinforces the point: the auto-mode classifier has access to the same context and concludes the action is benign, while default mode prompts. If nested skill invocation were genuinely security-relevant, both modes would treat it consistently.

Treating Skill() entries in allowed-tools differently from other entries makes sense only if the goal is to prevent skill authors from claiming transitive trust over child skills they did not author. That concern is real, but it must be addressed at skill-installation time (e.g., when the user installs the plugin), not at every invocation, because per-invocation prompts on a skill the user already approved at install time provide no additional information for the user to act on.

Related issues (showing this is a known structural pattern, not isolated)

  • #14956 — Skill allowed-tools doesn't grant permission for Bash commands (open). Same structural class: allowed-tools entries silently failing the permission check despite being parsed and reported as active. Different tool family (Bash) but same root cause shape.
  • #30949 — [DOCS] Skills docs should document interactive-tool exception to allowed-tools auto-approval behavior (open). The CHANGELOG for 2.1.69 introduced an undocumented exception ("interactive tools should not be silently auto-approved via allowed-tools"). Skill() may be in a similar undocumented-exception category.
  • #34419 — Feature: skill-scoped permissions (allowed-tools should auto-approve, not just restrict) (closed, not_planned). Establishes that allowed-tools auto-approval is an intentional supported feature, which makes the silent exclusion of Skill() a deviation from documented behavior rather than a missing feature.

Suggested resolution

Either:

  1. Honor Skill(child-name) in the parent skill's allowed-tools the same way other entries are honored — auto-approve nested skill invocation for the duration of the parent skill's execution, in all permission modes. This is the documented behavior and matches what auto mode already does.
  2. If exclusion is intentional, document the exception explicitly at https://code.claude.com/docs/en/skills under the allowed-tools section, list which tool categories are excluded (interactive tools per 2.1.69, Skill(), anything else), and explain the rationale — including why auto mode and default mode diverge.

Option 1 is the user-expected behavior and is consistent with the existing permission model. Option 2 is the minimum acceptable fallback if there is a security policy I am missing — but in that case the policy itself needs publication so plugin authors can stop relying on the (currently documented) auto-approval semantics for Skill() entries.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING