Chall-Manager's scenario decoding process does not check for zip slips
Description
Chall-Manager is a platform-agnostic system able to start Challenges on Demand of a player. When decoding a scenario (i.e. a zip archive), the path of the file to write is not checked, potentially leading to zip slips. Exploitation does not require authentication nor authorization, so anyone can exploit it. It should nonetheless not be exploitable as it is highly recommended to bury Chall-Manager deep within the infrastructure due to its large capabilities, so no users could reach the system. Patch has been implemented by commit 47d188f and shipped in v0.1.4.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/ctfer-io/chall-managerGo | < 0.1.4 | 0.1.4 |
Affected products
1- Range: < 0.1.4
Patches
147d188fda5e3fix: zip slip on scenario unzipping
1 file changed · +15 −3
pkg/scenario/io.go+15 −3 modified@@ -9,6 +9,7 @@ import ( "io" "os" "path/filepath" + "strings" errs "github.com/ctfer-io/chall-manager/pkg/errors" "github.com/pkg/errors" @@ -50,10 +51,13 @@ func Decode(ctx context.Context, challDir, scenario string) (string, error) { return cd, errors.Wrap(err, "base64 decoded invalid zip archive") } for _, f := range r.File { - filePath := filepath.Join(cd, f.Name) if f.FileInfo().IsDir() { continue } + filePath, err := sanitizeArchivePath(cd, f.Name) + if err != nil { + return cd, &errs.ErrInternal{Sub: err} + } // Save output directory i.e. the directory containing the Pulumi.yaml file, // the scenario entrypoint. @@ -74,15 +78,23 @@ func Decode(ctx context.Context, challDir, scenario string) (string, error) { } // Create and write the file - if err := copy(filePath, f); err != nil { + if err := copyTo(f, filePath); err != nil { return cd, &errs.ErrInternal{Sub: err} } } return outDir, Validate(ctx, outDir) } -func copy(filePath string, f *zip.File) error { +func sanitizeArchivePath(d, t string) (v string, err error) { + v = filepath.Join(d, t) + if strings.HasPrefix(v, filepath.Clean(d)) { + return v, nil + } + return "", fmt.Errorf("filepath is tainted: %s", t) +} + +func copyTo(f *zip.File, filePath string) error { outFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0777) if err != nil { return err
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-3gv2-v3jx-r9fhghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-53632ghsaADVISORY
- github.com/ctfer-io/chall-manager/commit/47d188fda5e3f86285e820f12ad9fb6f9930662cghsax_refsource_MISCWEB
- github.com/ctfer-io/chall-manager/releases/tag/v0.1.4ghsax_refsource_MISCWEB
- github.com/ctfer-io/chall-manager/security/advisories/GHSA-3gv2-v3jx-r9fhghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.