{"record":{"id":"47d91c4279da90e4","repo":"github/copilot-sdk","slug":"unsafe-runtime-asset-path-q","errorCode":null,"errorMessage":"unsafe runtime asset path %q","messagePattern":"unsafe runtime asset path %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/internal/embeddedcli/embeddedcli.go","lineNumber":397,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"opening runtime assets: %w\", err)\n\t}\n\tdefer gzipReader.Close()\n\ttarReader := tar.NewReader(gzipReader)\n\tfor {\n\t\theader, err := tarReader.Next()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"reading runtime assets: %w\", err)\n\t\t}\n\t\tif header.Typeflag != tar.TypeReg {\n\t\t\tcontinue\n\t\t}\n\t\tclean := filepath.Clean(filepath.FromSlash(header.Name))\n\t\tif !filepath.IsLocal(clean) {\n\t\t\treturn fmt.Errorf(\"unsafe runtime asset path %q\", header.Name)\n\t\t}\n\t\tcontent, err := io.ReadAll(tarReader)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"reading runtime asset %q: %w\", header.Name, err)\n\t\t}\n\t\tpath := filepath.Join(installDir, clean)\n\t\tif err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {\n\t\t\treturn fmt.Errorf(\"creating runtime asset directory: %w\", err)\n\t\t}\n\t\thash := sha256.Sum256(content)\n\t\tmode := os.FileMode(header.Mode & 0777)\n\t\tif err := installVerifiedFile(path, bytes.NewReader(content), hash[:], mode, \"runtime asset\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\truntimeAssetsInstalled = true\n\treturn nil\n}","sourceCodeStart":379,"sourceCodeEnd":415,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/internal/embeddedcli/embeddedcli.go#L379-L415","documentation":"For each regular file in the tar, installRuntimeAssets cleans the entry name and requires filepath.IsLocal(clean) before writing. Non-local names (absolute paths, '..' escapes) are rejected with \"unsafe runtime asset path\" to block path traversal / zip-slip extraction outside installDir.","triggerScenarios":"A tar entry header.Name is absolute (\"/etc/passwd\"), contains \"..\" (\"../../x\"), or otherwise resolves outside the install directory after filepath.Clean.","commonSituations":"A maliciously crafted or wrongly packaged runtime archive containing absolute or parent-relative paths; archives built on systems embedding absolute member names.","solutions":["Do not disable this check — the archive is untrusted or malformed","Repackage the runtime archive so all member names are relative and within the archive root","Inspect the archive (tar -tvf) to find the offending member and fix the packaging script","Only bypass via a vetted, trusted archive after security review"],"exampleFix":"// before\n// packaging script:\n// tar -czf runtime.tar.gz /abs/path/assets   // absolute members -> rejected\n// after\n// (cd /abs/path && tar -czf runtime.tar.gz assets) // relative members only","handlingStrategy":"validation","validationCode":"archive, _ := io.ReadAll(src)\n_ = iterateTarHeaders(archive, func(name string) error {\n    clean := filepath.Clean(filepath.FromSlash(name))\n    if !filepath.IsLocal(clean) {\n        return fmt.Errorf(\"archive contains unsafe member %q\", name)\n    }\n    return nil\n})","typeGuard":"func safeArchiveMember(name string) bool {\n    return filepath.IsLocal(filepath.Clean(filepath.FromSlash(name)))\n}","tryCatchPattern":"err := embeddedcli.InstallRuntime(ctx, cfg, dir)\nif err != nil && strings.Contains(err.Error(), \"unsafe runtime asset path\") {\n    return fmt.Errorf(\"refusing to install: runtime archive contains path-traversal members; repackage it\")\n}","preventionTips":["Package archives with relative member names only","Scan third-party archives for absolute/.. members before distributing","Never attempt to bypass the IsLocal check — it blocks zip-slip attacks"],"tags":["security","path-traversal","archive"],"backgroundTag":"path-traversal-blocked","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}