CVE-2025-54059
Description
melange allows users to build apk packages using declarative pipelines. Starting in version 0.23.0 and prior to version 0.29.5, SBOM files generated by melange in apks had file system permissions mode 666. This potentially allows an unprivileged user to tamper with apk SBOMs on a running image, potentially confusing security scanners. An attacker could also perform a DoS under special circumstances. Version 0.29.5 fixes the issue.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
chainguard.dev/melangeGo | >= 0.23.0, < 0.29.5 | 0.29.5 |
Affected products
1- Range: v0.1.0, v0.10.0, v0.10.1, …
Patches
3e29494b4a40afix: tighten up permissions for written SBOM files and signature tarballs (#2086)
3 files changed · +4 −4
pkg/build/build.go+1 −1 modified@@ -977,7 +977,7 @@ func (b Build) writeSBOM(pkgName string, doc *spdx.Document) error { pkgVersion := b.Configuration.Package.FullVersion() sbomPath := getPathForPackageSBOM(sbomDirPath, pkgName, pkgVersion) - f, err := b.WorkspaceDirFS.Create(sbomPath) + f, err := b.WorkspaceDirFS.OpenFile(sbomPath, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0o644) if err != nil { return fmt.Errorf("opening SBOM file for writing: %w", err) }
pkg/sign/apk.go+1 −1 modified@@ -129,7 +129,7 @@ func EmitSignature(signer ApkSigner, controlData []byte, sde time.Time) ([]byte, Name: signer.SignatureName(), Typeflag: tar.TypeReg, Size: int64(len(sig)), - Mode: int64(os.ModePerm), + Mode: int64(0o644), Uid: 0, Gid: 0, Uname: "root",
pkg/sign/apk_test.go+2 −2 modified@@ -161,15 +161,15 @@ func TestEmitSignature(t *testing.T) { Name: MockName, Typeflag: tar.TypeReg, Size: int64(len(controlData)), - Mode: int64(os.ModePerm), + Mode: int64(0o644), Uid: 0, Gid: 0, Uname: "root", Gname: "root", ModTime: sde, } if diff := cmp.Diff(hdr, hdrWant, cmpopts.IgnoreFields(tar.Header{}, "AccessTime", "ChangeTime", "Format")); diff != "" { - t.Errorf("Expected %v got %v", hdr, hdrWant) + t.Errorf("Expected %v got %v", hdrWant, hdr) } if hdr.Name != "mockiavelli" {
1b272db2a0bbPersist workspace filesystem throughout package builds (#1836)
14 files changed · +179 −169
e2e-tests/ipset-build-test.yaml+90 −0 added@@ -0,0 +1,90 @@ +package: + name: ipset + version: "7.22" + epoch: 3 + description: Manage Linux IP sets + copyright: + - license: GPL-2.0-only + +environment: + contents: + packages: + - autoconf + - automake + - build-base + - busybox + - ca-certificates-bundle + - libmnl-dev + - libtool + - linux-headers + - pkgconf-dev + +pipeline: + - uses: git-checkout + with: + repository: https://git.netfilter.org/ipset + tag: v${{package.version}} + expected-commit: a50abde9c959be364782c01c61429a951454f5ef + depth: "-1" + + - runs: | + ./autogen.sh + + - uses: autoconf/configure + with: + opts: | + --build=${{host.triplet.gnu}} \ + --host=${{host.triplet.gnu}} \ + --with-kmod=no \ + --prefix=/usr + + - uses: autoconf/make + + - uses: autoconf/make-install + + - uses: strip + +subpackages: + - name: ipset-dev + pipeline: + - uses: split/dev + dependencies: + runtime: + - ipset + description: ipset dev + test: + environment: + contents: + packages: + - busybox + pipeline: + - runs: | + test -e /usr/include/libipset/ipset.h + test -s /usr/include/libipset/ipset.h + - name: ipset-doc + pipeline: + - uses: split/manpages + description: ipset manpages + test: + environment: + contents: + packages: + - busybox + pipeline: + - runs: | + man ipset | head -n 10 + +update: + enabled: true + release-monitor: + identifier: 1393 + +test: + environment: + contents: + packages: + - busybox + pipeline: + - runs: | + ipset --help + ipset-translate --help
.github/workflows/wolfi-presubmit.yaml+1 −0 modified@@ -70,6 +70,7 @@ jobs: - s3cmd - perl-yaml-syck - ncurses + - fping # TODO: https://github.com/wolfi-dev/os/issues/26442 #- xmlto
go.mod+4 −4 modified@@ -3,7 +3,7 @@ module chainguard.dev/melange go 1.23.4 require ( - chainguard.dev/apko v0.25.3 + chainguard.dev/apko v0.25.4 cloud.google.com/go/storage v1.51.0 dagger.io/dagger v0.16.3 github.com/chainguard-dev/clog v1.7.0 @@ -42,7 +42,6 @@ require ( golang.org/x/crypto v0.36.0 golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa golang.org/x/sync v0.12.0 - golang.org/x/sys v0.31.0 golang.org/x/text v0.23.0 golang.org/x/time v0.11.0 google.golang.org/api v0.225.0 @@ -209,19 +208,20 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.34.0 // indirect go.opentelemetry.io/otel/trace v1.35.0 // indirect go.opentelemetry.io/proto/otlp v1.4.0 // indirect - go.step.sm/crypto v0.58.1 // indirect + go.step.sm/crypto v0.59.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/mod v0.23.0 // indirect golang.org/x/net v0.37.0 // indirect golang.org/x/oauth2 v0.28.0 // indirect + golang.org/x/sys v0.31.0 // indirect golang.org/x/term v0.30.0 // indirect google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/grpc v1.71.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - k8s.io/apimachinery v0.32.2 // indirect + k8s.io/apimachinery v0.32.3 // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect )
go.sum+6 −6 modified@@ -1,7 +1,7 @@ cel.dev/expr v0.19.2 h1:V354PbqIXr9IQdwy4SYA4xa0HXaWq1BUPAGzugBY5V4= cel.dev/expr v0.19.2/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= -chainguard.dev/apko v0.25.3 h1:wN8Ki/2s++XwK4E19x6MW1PIWq0I9j5gdZsVlp2NYBQ= -chainguard.dev/apko v0.25.3/go.mod h1:4i/zhP74WpHcGV8t9bQCueokNY27M9QRtocELa3aG8Y= +chainguard.dev/apko v0.25.4 h1:QFFCD7QR3q9AT5H+/ZCXQReCNN0CgRn1mkOq1T+FZfQ= +chainguard.dev/apko v0.25.4/go.mod h1:1xdjg538oPqb7VCiDMc4IlNtS5gRfpJqv2VIveR6wIo= chainguard.dev/go-grpc-kit v0.17.7 h1:TqHua7er5k8m6WM96y0Tm7IoLLkuZ5vh3+5SR1gruKg= chainguard.dev/go-grpc-kit v0.17.7/go.mod h1:JroMzTY9mdhKe/bvtyChgfECaNh80+bMZH3HS+TGXHw= chainguard.dev/sdk v0.1.31 h1:Blvpa0Ji/tC1VVV8/l8UyQe022LoRxZLfgasyFE1EhQ= @@ -534,8 +534,8 @@ go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= -go.step.sm/crypto v0.58.1 h1:2PpEYTbytA3el9dW0gh9uJEe/CR/J6wS+x2vWYLG83M= -go.step.sm/crypto v0.58.1/go.mod h1:yluOL5OqY7mXGGQ7JUmAv/6h8T8Ge3yXdlEESWHOqDQ= +go.step.sm/crypto v0.59.1 h1:jUL+5p19YS9YJKLaPUgkS2OdGm7s0+hwP7AqTFyF9Cg= +go.step.sm/crypto v0.59.1/go.mod h1:XHavmnzfTyPpQE/n4YokEtjiBzP3LZI9/1O061f5y0o= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -721,8 +721,8 @@ gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ= -k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= +k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
pkg/build/build.go+10 −7 modified@@ -101,6 +101,7 @@ type Build struct { SourceDateEpoch time.Time WorkspaceDir string + WorkspaceDirFS apkofs.FullFS WorkspaceIgnore string // Ordered directories where to find 'uses' pipelines. PipelineDirs []string @@ -311,6 +312,7 @@ func (b *Build) buildGuest(ctx context.Context, imgConfig apko_types.ImageConfig if b.Runner.Name() == container.QemuName { b.ExtraPackages = append(b.ExtraPackages, []string{ "melange-microvm-init", + "gnutar", }...) } @@ -626,7 +628,7 @@ func (b *Build) populateCache(ctx context.Context) error { defer os.RemoveAll(tmp) log.Infof("cache bucket copied to %s", tmp) - fsys := os.DirFS(tmp) + fsys := apkofs.DirFS(tmp) // mkdir /var/cache/melange if err := os.MkdirAll(b.CacheDir, 0o755); err != nil { @@ -842,7 +844,7 @@ func (b *Build) BuildPackage(ctx context.Context) error { } log.Infof("populating workspace %s from %s", b.WorkspaceDir, b.SourceDir) - if err := b.populateWorkspace(ctx, os.DirFS(b.SourceDir)); err != nil { + if err := b.populateWorkspace(ctx, apkofs.DirFS(b.SourceDir)); err != nil { return fmt.Errorf("unable to populate workspace: %w", err) } } @@ -949,8 +951,9 @@ func (b *Build) BuildPackage(ctx context.Context) error { // Retrieve the post build workspace from the runner log.Infof("retrieving workspace from builder: %s", cfg.PodID) - fsys := apkofs.DirFS(b.WorkspaceDir) - if err := b.retrieveWorkspace(ctx, fsys); err != nil { + b.WorkspaceDirFS = apkofs.DirFS(b.WorkspaceDir) + + if err := b.retrieveWorkspace(ctx, b.WorkspaceDirFS); err != nil { return fmt.Errorf("retrieving workspace: %w", err) } log.Infof("retrieved and wrote post-build workspace to: %s", b.WorkspaceDir) @@ -1070,15 +1073,15 @@ func (b *Build) BuildPackage(ctx context.Context) error { // filesystem in the directory `/var/lib/db/sbom`. The pkgName parameter should // be set to the name of the origin package or subpackage. func (b Build) writeSBOM(pkgName string, doc *spdx.Document) error { - apkFSPath := filepath.Join(b.WorkspaceDir, melangeOutputDirName, pkgName) + apkFSPath := filepath.Join(melangeOutputDirName, pkgName) sbomDirPath := filepath.Join(apkFSPath, "/var/lib/db/sbom") - if err := os.MkdirAll(sbomDirPath, os.FileMode(0o755)); err != nil { + if err := b.WorkspaceDirFS.MkdirAll(sbomDirPath, os.FileMode(0o755)); err != nil { return fmt.Errorf("creating SBOM directory: %w", err) } pkgVersion := b.Configuration.Package.FullVersion() sbomPath := getPathForPackageSBOM(sbomDirPath, pkgName, pkgVersion) - f, err := os.Create(sbomPath) + f, err := b.WorkspaceDirFS.Create(sbomPath) if err != nil { return fmt.Errorf("opening SBOM file for writing: %w", err) }
pkg/build/package.go+8 −4 modified@@ -30,6 +30,7 @@ import ( "strings" "text/template" + apkofs "chainguard.dev/apko/pkg/apk/fs" apko_types "chainguard.dev/apko/pkg/build/types" "github.com/klauspost/compress/gzip" @@ -371,7 +372,7 @@ func combine(out io.Writer, inputs ...io.Reader) error { } // TODO(kaniini): generate APKv3 packages -func (pc *PackageBuild) calculateInstalledSize(fsys fs.FS) error { +func (pc *PackageBuild) calculateInstalledSize(fsys apkofs.FullFS) error { if err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { if err != nil { return err @@ -391,7 +392,7 @@ func (pc *PackageBuild) calculateInstalledSize(fsys fs.FS) error { return nil } -func (pc *PackageBuild) emitDataSection(ctx context.Context, fsys fs.FS, userinfofs fs.FS, remapUIDs map[int]int, remapGIDs map[int]int, w io.WriteSeeker) error { +func (pc *PackageBuild) emitDataSection(ctx context.Context, fsys apkofs.FullFS, userinfofs apkofs.FullFS, remapUIDs map[int]int, remapGIDs map[int]int, w io.WriteSeeker) error { log := clog.FromContext(ctx) tarctx, err := tarball.NewContext( tarball.WithSourceDateEpoch(pc.Build.SourceDateEpoch), @@ -445,10 +446,13 @@ func (pc *PackageBuild) EmitPackage(ctx context.Context) error { log.Info("generating package " + pc.Identity()) // filesystem for the data package - fsys := readlinkFS(pc.WorkspaceSubdir()) + fsys, err := apkofs.Sub(pc.Build.WorkspaceDirFS, filepath.Join(melangeOutputDirName, pc.PackageName)) + if err != nil { + return fmt.Errorf("failed to return filesystem for workspace subtree: %w", err) + } // provide the tar writer etc/passwd and etc/group of guest filesystem - userinfofs := os.DirFS(pc.Build.GuestDir) + userinfofs := apkofs.DirFS(pc.Build.GuestDir) hdl := &SCABuildInterface{ PackageBuild: pc,
pkg/build/readlinkfs.go+0 −142 removed@@ -1,142 +0,0 @@ -// Copyright 2022, 2023 Chainguard, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build - -import ( - "io/fs" - "os" - "path/filepath" - - apkofs "chainguard.dev/apko/pkg/apk/fs" - "golang.org/x/sys/unix" -) - -type rlfs struct { - apkofs.XattrFS - - base string - f fs.FS -} - -func (f *rlfs) Readlink(name string) (string, error) { - target, err := os.Readlink(filepath.Join(f.base, name)) - if err != nil { - return "", err - } - return target, nil -} - -func (f *rlfs) Open(name string) (fs.File, error) { - return f.f.Open(name) -} - -func (f *rlfs) Stat(name string) (fs.FileInfo, error) { - return os.Stat(filepath.Join(f.base, name)) -} - -func (f *rlfs) SetXattr(path string, attr string, data []byte) error { - return unix.Setxattr(filepath.Join(f.base, path), attr, data, 0) -} - -func (f *rlfs) GetXattr(path string, attr string) ([]byte, error) { - realPath := filepath.Join(f.base, path) - - size, err := unix.Getxattr(realPath, attr, nil) - if err != nil { - return []byte{}, err - } - - buf := make([]byte, size) - _, err = unix.Getxattr(realPath, attr, buf) - if err != nil { - return []byte{}, err - } - - return buf, nil -} - -func (f *rlfs) RemoveXattr(path string, attr string) error { - return unix.Removexattr(filepath.Join(f.base, path), attr) -} - -// stringsFromByteSlice converts a sequence of attributes to a []string. -// On Linux, each entry is a NULL-terminated string. -// Taken from golang.org/x/sys/unix/syscall_linux_test.go. -func stringsFromByteSlice(buf []byte) []string { - var result []string - off := 0 - for i, b := range buf { - if b == 0 { - result = append(result, string(buf[off:i])) - off = i + 1 - } - } - return result -} - -// xattrIgnoreList contains a mapping of xattr names used by various -// security features which leak their state into packages. We need to -// ignore these xattrs because they require special permissions to be -// set when the underlying security features are in use. -var xattrIgnoreList = map[string]bool{ - "com.apple.provenance": true, - "security.csm": true, - "security.selinux": true, - "com.docker.grpcfuse.ownership": true, -} - -func (f *rlfs) ListXattrs(path string) (map[string][]byte, error) { - realPath := filepath.Join(f.base, path) - - size, err := unix.Listxattr(realPath, nil) - if err != nil { - return map[string][]byte{}, err - } - - // If the xattr list is empty, the size will be 0. - if size <= 0 { - return map[string][]byte{}, nil - } - - buf := make([]byte, size) - read, err := unix.Listxattr(realPath, buf) - if err != nil { - return map[string][]byte{}, err - } - - xattrMap := map[string][]byte{} - xattrNames := stringsFromByteSlice(buf[:read]) - for _, xattrName := range xattrNames { - if _, ok := xattrIgnoreList[xattrName]; ok { - continue - } - - result, err := f.GetXattr(path, xattrName) - if err != nil { - return map[string][]byte{}, err - } - - xattrMap[xattrName] = result - } - - return xattrMap, nil -} - -func readlinkFS(dir string) apkofs.ReadLinkFS { - return &rlfs{ - base: dir, - f: os.DirFS(dir), - } -}
pkg/build/sca_interface.go+5 −2 modified@@ -18,6 +18,7 @@ import ( "fmt" "path/filepath" + apkofs "chainguard.dev/apko/pkg/apk/fs" "chainguard.dev/melange/pkg/config" "chainguard.dev/melange/pkg/sca" ) @@ -54,8 +55,10 @@ func (scabi *SCABuildInterface) Version() string { // FilesystemForRelative implements an abstract filesystem for any of the packages being // built. func (scabi *SCABuildInterface) FilesystemForRelative(pkgName string) (sca.SCAFS, error) { - pkgDir := filepath.Join(scabi.PackageBuild.Build.WorkspaceDir, melangeOutputDirName, pkgName) - rlFS := readlinkFS(pkgDir) + rlFS, err := apkofs.Sub(scabi.PackageBuild.Build.WorkspaceDirFS, filepath.Join(melangeOutputDirName, pkgName)) + if err != nil { + return nil, fmt.Errorf("package build subFS: %w", err) + } scaFS, ok := rlFS.(sca.SCAFS) if !ok { return nil, fmt.Errorf("SCAFS not implemented")
pkg/build/test.go+3 −2 modified@@ -311,7 +311,7 @@ func (t *Test) PopulateWorkspace(ctx context.Context, src fs.FS) error { log.Infof("populating workspace %s from %s", t.WorkspaceDir, t.SourceDir) - fsys := os.DirFS(t.SourceDir) + fsys := apkofs.DirFS(t.SourceDir) return fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { if err != nil { @@ -349,6 +349,7 @@ func (t *Test) TestPackage(ctx context.Context) error { if t.Runner.Name() == container.QemuName { t.ExtraTestPackages = append(t.ExtraTestPackages, []string{ "melange-microvm-init", + "gnutar", }...) } @@ -425,7 +426,7 @@ func (t *Test) TestPackage(ctx context.Context) error { return fmt.Errorf("mkdir -p %s: %w", t.WorkspaceDir, err) } - if err := t.PopulateWorkspace(ctx, os.DirFS(t.SourceDir)); err != nil { + if err := t.PopulateWorkspace(ctx, apkofs.DirFS(t.SourceDir)); err != nil { return fmt.Errorf("unable to populate workspace: %w", err) } }
pkg/config/schema.json+45 −0 modified@@ -35,6 +35,40 @@ ], "description": "BuildOption describes an optional deviation to a package build." }, + "CPE": { + "properties": { + "part": { + "type": "string" + }, + "vendor": { + "type": "string" + }, + "product": { + "type": "string" + }, + "edition": { + "type": "string" + }, + "language": { + "type": "string" + }, + "sw_edition": { + "type": "string" + }, + "target_sw": { + "type": "string" + }, + "target_hw": { + "type": "string" + }, + "other": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "description": "CPE stores values used to produce a CPE to describe the package, suitable for matching against NVD records." + }, "Capabilities": { "properties": { "add": { @@ -530,6 +564,13 @@ "type": "string", "description": "A human-readable description of the package" }, + "annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations for this package" + }, "url": { "type": "string", "description": "The URL to the package's homepage" @@ -568,6 +609,10 @@ "$ref": "#/$defs/Checks", "description": "Optional: enabling, disabling, and configuration of build checks" }, + "cpe": { + "$ref": "#/$defs/CPE", + "description": "The CPE field values to be used for matching against NVD vulnerability\nrecords, if known." + }, "timeout": { "type": "integer", "description": "Optional: The amount of time to allow this build to take before timing out."
pkg/container/qemu_runner.go+1 −1 modified@@ -234,7 +234,7 @@ func (bw *qemu) WorkspaceTar(ctx context.Context, cfg *Config) (io.ReadCloser, e nil, outFile, false, - []string{"sh", "-c", "cd /home/build && tar cvzf - melange-out"}, + []string{"sh", "-c", "cd /home/build && tar cvpzf - --xattrs --acls melange-out"}, ) if err != nil { return nil, err
pkg/linter/linter.go+2 −1 modified@@ -29,6 +29,7 @@ import ( "slices" "strings" + apkofs "chainguard.dev/apko/pkg/apk/fs" "github.com/chainguard-dev/clog" "github.com/dustin/go-humanize" "golang.org/x/exp/maps" @@ -677,7 +678,7 @@ func LintBuild(ctx context.Context, cfg *config.Configuration, packageName strin } log := clog.FromContext(ctx) - fsys := os.DirFS(path) + fsys := apkofs.DirFS(path) if err := lintPackageFS(ctx, cfg, packageName, fsys, warn); err != nil { log.Warn(err.Error())
pkg/sca/sca.go+4 −0 modified@@ -731,6 +731,10 @@ func generateShbangDeps(ctx context.Context, hdl SCAHandle, generated *config.De return err } + if d.Type()&fs.ModeSymlink == fs.ModeSymlink { + return nil + } + if !strings.HasPrefix(path, "usr/bin/") && !strings.HasPrefix(path, "bin/") { return nil }
pkg/sca/testdata/generated/x86_64/shbang-test-1-r1.apk+0 −0 modified
2c649a99da75Vulnerability 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
9- github.com/advisories/GHSA-5662-cv6m-63whghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-54059ghsaADVISORY
- github.com/chainguard-dev/melange/commit/1b272db2a0bb3441553284cc56d87236b4b64c04nvdWEB
- github.com/chainguard-dev/melange/commit/e29494b4a40a91619ec1c87a09003c6d5164cea1nvdWEB
- github.com/chainguard-dev/melange/pull/1836nvdWEB
- github.com/chainguard-dev/melange/pull/2086nvdWEB
- github.com/chainguard-dev/melange/releases/tag/v0.29.5nvdWEB
- github.com/chainguard-dev/melange/security/advisories/GHSA-5662-cv6m-63whnvdWEB
- github.com/chainguard-dev/melange/releases/tag/v0.23.0nvd
News mentions
0No linked articles in our index yet.