#21839: fix(skills): allowBundled: [] now blocks all bundled skills
gateway
agents
size: M
Cluster:
Bundled Skills Management
## Summary
Setting `skills.allowBundled: []` had no effect — all bundled skills remained eligible. An empty array was treated identically to an unconfigured (undefined) allowlist.
## Root Cause
Two compounding issues in `src/agents/skills/config.ts`:
1. **`normalizeAllowlist()`** collapsed `[]` to `undefined` via `normalized.length > 0 ? normalized : undefined`, erasing the explicit empty-array signal before it could be checked downstream.
2. **`isBundledSkillAllowed()`** treated `!allowlist` and `allowlist.length === 0` identically — both returned `true` (allow all).
## Fix
- `normalizeAllowlist()` now returns the normalized array directly, preserving `[]` as a meaningful value.
- `isBundledSkillAllowed()` only short-circuits on `!allowlist` (undefined = not configured). An empty array falls through to `allowlist.includes(key)`, which naturally returns `false` for all bundled skills. The existing `!isBundledSkill(entry)` guard still allows workspace skills through regardless.
## Changes
- `src/agents/skills/config.ts` — 2-line fix
- `src/agents/skills/config.test.ts` — 8 new unit tests
## Tests
| Scenario | Result |
|---|---|
| `allowBundled: undefined` → all skills allowed | ✅ |
| `allowBundled: []` → all bundled blocked | ✅ |
| `allowBundled: []` → workspace skills unaffected | ✅ |
| `allowBundled: ["weather"]` → only weather allowed | ✅ |
| Workspace skills never blocked by allowlist | ✅ |
| `resolveBundledAllowlist` preserves undefined vs [] | ✅ |
All 13 skill tests pass (8 new + 5 existing).
Fixes #21709
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR fixes a bug where setting `skills.allowBundled: []` had no effect - all bundled skills remained eligible. The root cause was twofold: `normalizeAllowlist()` collapsed empty arrays to `undefined`, and `isBundledSkillAllowed()` treated both `undefined` and empty arrays as "allow all". The fix preserves the empty array signal and only treats `undefined` as unconfigured. Comprehensive unit tests validate the fix across undefined, empty, and populated allowlist scenarios for both bundled and workspace skills.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The fix is surgical (2 lines changed), logically sound, and backed by comprehensive unit tests covering all edge cases. The change correctly distinguishes between unconfigured (undefined) and explicitly empty ([]) allowlists. The PR only modifies the skills allowlist logic and adds corresponding tests - no behavioral regressions expected.
- No files require special attention
<sub>Last reviewed commit: 1cd52df</sub>
<!-- greptile_other_comments_section -->
<sub>(5/5) You can turn off certain types of comments like style [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#22198: fix(skills): treat empty allowBundled array as block-all
by haitao-sjsu · 2026-02-20
93.3%
#21727: skills: treat allowBundled [] as denylist for bundled skills
by AIflow-Labs · 2026-02-20
91.9%
#17062: fix(telegram): prioritize workspace skills over bundled in native c...
by scout-wolfe · 2026-02-15
80.5%
#21745: tools: fix image inbound resolution and empty allowBundled
by AIflow-Labs · 2026-02-20
80.3%
#8075: fix(skills): add --ignore-scripts to all package managers
by yubrew · 2026-02-03
79.4%
#22525: [Bug]: Session snapshot not reloading skills after gateway restart ...
by zwffff · 2026-02-21
79.2%
#10016: fix: prevent FD exhaustion from skill watcher scanning artifact trees
by oldeucryptoboi · 2026-02-06
78.9%
#12076: fix(skills): recursive directory filtering to actually exclude venv...
by xiaoyaner0201 · 2026-02-08
78.8%
#12956: fix: guard .trim() calls on potentially undefined workspaceDir
by omair445 · 2026-02-10
78.8%
#19707: fix(agents): apply per-agent skills filter to all run paths
by mcaxtr · 2026-02-18
78.4%