From 4650fcef5925e9860b18f6f107d5fb5b82da2198 Mon Sep 17 00:00:00 2001 From: "Matthew (Pilot Protocol)" Date: Thu, 18 Jun 2026 08:41:21 +0000 Subject: [PATCH] fix(security): add decompression bomb protection to untarUnder (PILOT-418) The untarUnder function used io.Copy without a per-file size limit when extracting tar.gz entries from app store catalogue bundles. While the HTTP download is capped at 1 MiB, a maliciously crafted archive with an extreme compression ratio could fill disk. Fix: wrap tar entry extraction with io.LimitReader(tr, 64<<20) for a 64 MiB per-file maximum. Closes PILOT-418 --- cmd/pilotctl/appstore_catalogue.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd/pilotctl/appstore_catalogue.go b/cmd/pilotctl/appstore_catalogue.go index 40fa1245..183ca841 100644 --- a/cmd/pilotctl/appstore_catalogue.go +++ b/cmd/pilotctl/appstore_catalogue.go @@ -417,7 +417,10 @@ func httpGet(raw string) (io.ReadCloser, error) { // untarUnder writes every entry in r under dst, refusing any path // that resolves outside dst (mirrors the supervisor's -// resolveUnder guard on manifest.binary.path). +// resolveUnder guard on manifest.binary.path). Each extracted file +// is capped at maxExtractBytes to prevent decompression bomb attacks. +const maxExtractBytes = 64 << 20 // 64 MiB per-file cap + func untarUnder(r io.Reader, dst string) error { tr := tar.NewReader(r) for { @@ -446,7 +449,7 @@ func untarUnder(r io.Reader, dst string) error { if err != nil { return err } - if _, err := io.Copy(f, tr); err != nil { + if _, err := io.Copy(f, io.LimitReader(tr, maxExtractBytes)); err != nil { _ = f.Close() return err }