Marketplace: validate tree entry names and cap depth/manifest size
Fix round 1 from PR review of the tree/catalog parsing: - collect_dir now rejects an entry whose name is ".", "..", empty, or contains "/", "\" or NUL before it becomes part of an item's rel_path — a crafted git tree could otherwise walk a file outside the item's own folder once that path is joined against the item root downstream. - collect_dir caps recursion at 32 directory levels and counts directories (not just files) toward MAX_ITEM_FILES, so a tree that is wide or deep rather than merely file-heavy is still bounded. - hook.json and plugins/.claude-plugin/marketplace.json are now rejected unparsed above 1 MiB, rather than handed to serde_json regardless of size. A pre-read size query (checking a blob's size before reading it) is deferred per controller ruling — this round reads the blob and checks its length before parsing, which is enough for the JSON-parsing DoS shape being closed here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -92,6 +92,29 @@ impl MemTree {
|
||||
self
|
||||
}
|
||||
|
||||
/// Place a file so that, inside `dir`, it is listed under the literal
|
||||
/// entry name `name` — including a name `file`/`exec_file`/`symlink`
|
||||
/// could never be asked to produce because it doesn't correspond to any
|
||||
/// real filesystem path a caller here would construct: `.`, `..`, empty,
|
||||
/// or containing `/`, `\` or a NUL byte. Exists only so a test can drive
|
||||
/// `catalog::collect_dir`'s hostile-entry-name rejection without relying
|
||||
/// on incidental behaviour of path-string splitting.
|
||||
pub fn raw_named_file(mut self, dir: &str, name: &str, contents: &str) -> Self {
|
||||
let path = if dir.is_empty() {
|
||||
name.to_string()
|
||||
} else {
|
||||
format!("{}/{}", dir, name)
|
||||
};
|
||||
self.nodes.insert(
|
||||
path,
|
||||
MemNode::File {
|
||||
data: contents.as_bytes().to_vec(),
|
||||
executable: false,
|
||||
},
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
fn is_dir(&self, path: &str) -> bool {
|
||||
if path.is_empty() {
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user