Merged
Conversation
The skill packager's collectSkillFiles() function walks a directory and reads all files into memory. Without limits, a maliciously crafted or excessively large skill directory could exhaust memory during packaging. Add two limits to collectSkillFiles(): - maxSkillFiles (1,000): caps the number of files, aligned with the extraction-side MaxExtractFileCount in toolhive/pkg/skills/installer.go - maxSkillTotalSize (100 MB): caps the aggregate size of all file contents, aligned with existing blob/decompression limits in this package (MaxBlobSize, MaxDecompressedSize) These limits complement the existing per-file and per-blob limits that already protect the extraction and registry paths, closing a gap on the packaging (build) side. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
rdimitrov
approved these changes
Feb 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The skill packager's
collectSkillFiles()function walks a skill directory and reads all file contents into memory before building the OCI artifact. Without limits, a maliciously crafted or excessively large skill directory could exhaust memory during theBuildoperation exposed via thethv serveAPI.The gap
toolhive-core already has comprehensive size limits on the extraction and registry paths:
MaxDecompressedSizegzip.goMaxTarFileSizetar.goMaxBlobSizeregistry.goMaxManifestSizeregistry.gomaxFrontmatterSizepackager.goAnd toolhive adds extraction-side limits:
MaxTotalExtractSizeinstaller.goMaxFileExtractSizeinstaller.goMaxExtractFileCountinstaller.goHowever, the packaging (build) side had no file count or aggregate size limit. This meant the memory exhaustion could happen before any of the downstream limits had a chance to trigger.
What this PR adds
Two limits to
collectSkillFiles():maxSkillFiles= 1,000 — caps the number of files collected. Aligned withMaxExtractFileCountin toolhive so that anything that can be packaged can also be extracted.maxSkillTotalSize= 100 MB — caps the total aggregate size of all file contents read into memory. Aligned withMaxBlobSizeandMaxDecompressedSizein this package.Both limits are checked incrementally during the directory walk, so the function fails fast without reading the entire directory.
Test plan
TestCollectSkillFiles_ExceedsMaxFiles— creates 1,001 files (one over the limit), verifies the errortask test— all tests pass (including race detector)task lint— 0 issues🤖 Generated with Claude Code