mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-07-26 11:49:16 +00:00
fix(docker): upgrade CLI to v29.4.1 and Compose to v5.1.3, clear VEX (#836)
* fix(docker): upgrade CLI to v29.4.1 and Compose to v5.1.3, clear VEX * fix(vex): restore CVE-2026-34040 not_affected statement for compose * fix: correct VEX product matching for CVE-2026-34040
This commit is contained in:
@@ -154,14 +154,10 @@ jobs:
|
||||
- name: Scan image for vulnerabilities (Trivy)
|
||||
# Hard-fails the PR on any HIGH or CRITICAL finding not suppressed by
|
||||
# the OpenVEX document at security/vex/sencho.openvex.json (loaded via
|
||||
# trivy.yaml) or by .trivyignore at the repo root. The VEX document is
|
||||
# the canonical triage record and is also attached as a cosign
|
||||
# attestation on the published image. .trivyignore exists only to
|
||||
# mirror VEX entries that cannot be resolved here because Trivy does
|
||||
# not emit an OCI purl for local images without a digest, so VEX
|
||||
# product matching against `sencho:pr-test` is a no-op (see
|
||||
# aquasecurity/trivy#9399). Add the VEX statement first, then mirror
|
||||
# the CVE id in .trivyignore with a pointer to the VEX justification.
|
||||
# trivy.yaml). The VEX document is the canonical triage record and is
|
||||
# also attached as a cosign attestation on the published image.
|
||||
# If a new CVE must be triaged, add a VEX statement with a
|
||||
# justification — do NOT recreate .trivyignore.
|
||||
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
||||
with:
|
||||
image-ref: sencho:pr-test
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# Trivy ignore list (CI build-and-scan only)
|
||||
#
|
||||
# The OpenVEX document at security/vex/sencho.openvex.json is the canonical
|
||||
# source of truth for accepted CVEs. It is consumed by Trivy via trivy.yaml
|
||||
# and attached as a cosign attestation on every published image, so any
|
||||
# downstream consumer who scans saelix/sencho:<tag> sees the same triage.
|
||||
#
|
||||
# This file exists only because the OpenVEX product purl matching does not
|
||||
# resolve for locally-built images that have no RepoDigests. Trivy does not
|
||||
# generate an OCI purl for such images (see aquasecurity/trivy#9399), so the
|
||||
# product `pkg:oci/sencho` in our VEX statements never matches the artifact
|
||||
# under test in the PR-time scan against `sencho:pr-test`. Once the image is
|
||||
# pushed and acquires a digest, VEX matching resolves and this file is no
|
||||
# longer load-bearing for that scan.
|
||||
#
|
||||
# Rule: every entry here MUST already have a corresponding statement in
|
||||
# security/vex/sencho.openvex.json with a justification. Do not add a CVE
|
||||
# here without first adding the VEX statement; the VEX file is what users
|
||||
# audit, not this one.
|
||||
|
||||
# Justification: covered by VEX statement for CVE-2026-39883 (otel/sdk
|
||||
# BSD kenv PATH hijacking). The vulnerable code path executes only on
|
||||
# BSD operating systems and Sencho ships linux/amd64 + linux/arm64 only.
|
||||
# See security/vex/sencho.openvex.json for the full impact statement.
|
||||
CVE-2026-39883
|
||||
|
||||
# Justification: covered by VEX statement for CVE-2026-34040 (Moby authz
|
||||
# bypass on oversized request body). compose v5.1.2 bundles the legacy
|
||||
# github.com/docker/docker@v28.5.2+incompatible as a client-side library
|
||||
# for API types and codecs; the daemon-side authz hook code path the CVE
|
||||
# affects is unreachable from a CLI client. The advisory's fix in
|
||||
# Docker Engine 29.3.1 ships under the new github.com/moby/moby/v2
|
||||
# module path which compose v5.1.2 does not yet import, so v28.5.2 is
|
||||
# the only Go-module-resolvable version reachable from compose. See
|
||||
# security/vex/sencho.openvex.json for the full impact statement.
|
||||
CVE-2026-34040
|
||||
+42
-34
@@ -92,25 +92,24 @@ RUN if [ "$TARGETARCH" = "$BUILDARCH" ]; then \
|
||||
|
||||
# Stage 4a: Build Docker CLI from source against Go 1.26.2
|
||||
#
|
||||
# Resolves the following CVEs that were present in the upstream static Docker CLI
|
||||
# binary (which ships with Go 1.26.1):
|
||||
# CVE-2026-32280/32281/32282/32283: Go stdlib x509/TLS issues (fixed in Go 1.26.2)
|
||||
# CVE-2026-33810: Go stdlib DNS name constraint bypass (fixed in Go 1.26.2)
|
||||
# CVE-2026-33186: grpc 1.78.0 HTTP/2 server attack (CLI is client-only;
|
||||
# removed from SBOM by building with go mod's updated resolution)
|
||||
# CLI v29.4.1 ships otel/sdk v1.43.0, resolving CVE-2026-39883 (BSD kenv) and
|
||||
# CVE-2026-39882 (OTLP response OOM). It also carries the CVE-2025-15558 fix
|
||||
# (Windows plugin search path LPE, fixed since v29.2.0). Building from source
|
||||
# with Go 1.26.2 additionally eliminates Go stdlib CVEs present in the upstream
|
||||
# static binary.
|
||||
#
|
||||
# Runs on the BUILD platform; GOARCH cross-compiles the static binary for TARGET.
|
||||
# The --depth 1 clone fetches only the v29.4.0 tag commit, minimising transfer size.
|
||||
# docker/cli v29.4.0 uses CalVer and ships vendor.mod instead of go.mod to avoid
|
||||
# SemVer compliance requirements. We copy vendor.mod -> go.mod and build with
|
||||
# -mod=vendor so all deps come from the vendored tree (no network access needed).
|
||||
# The --depth 1 clone fetches only the v29.4.1 tag commit, minimising transfer size.
|
||||
# docker/cli uses CalVer and ships vendor.mod instead of go.mod to avoid SemVer
|
||||
# compliance requirements. We copy vendor.mod -> go.mod and build with -mod=vendor
|
||||
# so all deps come from the vendored tree (no network access needed).
|
||||
FROM --platform=$BUILDPLATFORM golang:1.26-alpine@sha256:f85330846cde1e57ca9ec309382da3b8e6ae3ab943d2739500e08c86393a21b1 AS cli-builder
|
||||
|
||||
ARG TARGETARCH
|
||||
|
||||
RUN apk add --no-cache git
|
||||
|
||||
RUN git clone --depth 1 --branch v29.4.0 https://github.com/docker/cli.git /src/docker-cli
|
||||
RUN git clone --depth 1 --branch v29.4.1 https://github.com/docker/cli.git /src/docker-cli
|
||||
|
||||
WORKDIR /src/docker-cli
|
||||
|
||||
@@ -120,50 +119,59 @@ RUN cp vendor.mod go.mod && cp vendor.sum go.sum && \
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} go build \
|
||||
-mod=vendor \
|
||||
-ldflags "-extldflags=-static \
|
||||
-X github.com/docker/cli/cli/version.Version=29.4.0 \
|
||||
-X github.com/docker/cli/cli/version.Version=29.4.1 \
|
||||
-X github.com/docker/cli/cli/version.GitCommit=source-go1.26.2" \
|
||||
-o /build/docker \
|
||||
./cmd/docker
|
||||
|
||||
# Stage 4b: Build Docker Compose from source against Go 1.26.2
|
||||
#
|
||||
# Rebuilding compose with the same patched Go toolchain eliminates any Go stdlib
|
||||
# CVEs that would otherwise appear in the compose binary's SBOM. Vendored
|
||||
# third-party dependencies inside compose (buildkit, moby/docker, otel) are
|
||||
# not reachable via Sencho's compose invocations (up/down/ps only); those
|
||||
# residual CVEs are documented in security/vex/sencho.openvex.json.
|
||||
# Compose v5.1.3 removed the direct dependency on github.com/docker/docker
|
||||
# (replaced by moby/moby/api + moby/moby/client), eliminating CVE-2026-34040
|
||||
# and CVE-2026-33997 at the dependency level. Rebuilding with the patched Go
|
||||
# toolchain eliminates Go stdlib CVEs from the binary's SBOM.
|
||||
#
|
||||
# Compose v5.1.3 still bundles otel/sdk v1.42.0 transitively via buildkit
|
||||
# v0.29.0. The go get step below bumps otel to v1.43.0 to resolve
|
||||
# CVE-2026-39883 (BSD kenv) and CVE-2026-39882 (OTLP response OOM) so that
|
||||
# the compose binary scans completely clean.
|
||||
FROM --platform=$BUILDPLATFORM golang:1.26-alpine@sha256:f85330846cde1e57ca9ec309382da3b8e6ae3ab943d2739500e08c86393a21b1 AS compose-builder
|
||||
|
||||
ARG TARGETARCH
|
||||
|
||||
RUN apk add --no-cache git
|
||||
|
||||
RUN git clone --depth 1 --branch v5.1.2 https://github.com/docker/compose.git /src/docker-compose
|
||||
RUN git clone --depth 1 --branch v5.1.3 https://github.com/docker/compose.git /src/docker-compose
|
||||
|
||||
WORKDIR /src/docker-compose
|
||||
|
||||
RUN mkdir -p /build
|
||||
|
||||
# Build target is ./cmd (the package main with plugin.Run), per docker/compose
|
||||
# v5.1.2's Makefile. The directory ./cmd/compose is package compose (cobra
|
||||
# command definitions only, not main). The module path moved from /v2 to /v5
|
||||
# in the v5 release, so the Version ldflag must reference /v5/internal.
|
||||
#
|
||||
# The bundled github.com/docker/docker dependency stays at v28.5.2+incompatible
|
||||
# (compose v5.1.2's go.mod). It cannot be upgraded to docker-v29.3.1 (the
|
||||
# release that contains the CVE-2026-34040 authz fix) because moby/moby's
|
||||
# docker-29.x branch declares its module path as github.com/moby/moby/v2,
|
||||
# making it unreachable through the legacy github.com/docker/docker import
|
||||
# that compose v5.1.2 still uses. The Go module proxy reflects this and lists
|
||||
# v28.5.2+incompatible as the highest resolvable version. The CVE only affects
|
||||
# Docker Engine's daemon authz hook code path; compose runs as a CLI client
|
||||
# and never executes that path. See security/vex/sencho.openvex.json for the
|
||||
# full not_affected justification, which Trivy honours via trivy.yaml.
|
||||
# Patch otel/sdk and exporters from v1.42.0 → v1.43.0 to clear CVE-2026-39883
|
||||
# and CVE-2026-39882. This is a targeted security bump; otel 1.42→1.43 is a
|
||||
# patch-level fix with no breaking API changes.
|
||||
RUN --mount=type=cache,id=go-mod,sharing=locked,target=/go/pkg/mod \
|
||||
go get go.opentelemetry.io/otel@v1.43.0 \
|
||||
go.opentelemetry.io/otel/sdk@v1.43.0 \
|
||||
go.opentelemetry.io/otel/sdk/metric@v1.43.0 \
|
||||
go.opentelemetry.io/otel/metric@v1.43.0 \
|
||||
go.opentelemetry.io/otel/trace@v1.43.0 \
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace@v1.43.0 \
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@v1.43.0 \
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp@v1.43.0 \
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc@v1.43.0 \
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp@v1.43.0 && \
|
||||
go mod tidy
|
||||
|
||||
# Build target is ./cmd (the package main with plugin.Run), per docker/compose's
|
||||
# Makefile. The directory ./cmd/compose is package compose (cobra command
|
||||
# definitions only, not main). The module path moved from /v2 to /v5 in the
|
||||
# v5 release, so the Version ldflag must reference /v5/internal.
|
||||
RUN --mount=type=cache,id=go-mod,sharing=locked,target=/go/pkg/mod \
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} go build \
|
||||
-trimpath \
|
||||
-ldflags "-s -w -extldflags=-static \
|
||||
-X github.com/docker/compose/v5/internal.Version=v5.1.2" \
|
||||
-X github.com/docker/compose/v5/internal.Version=v5.1.3" \
|
||||
-o /build/docker-compose \
|
||||
./cmd
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"@id": "https://github.com/AnsoCode/Sencho/security/vex/sencho.openvex.json",
|
||||
"author": "Studio Saelix",
|
||||
"role": "Vendor",
|
||||
"timestamp": "2026-04-26T00:00:00Z",
|
||||
"last_updated": "2026-04-27T00:00:00Z",
|
||||
"version": 2,
|
||||
"timestamp": "2026-04-29T00:00:00Z",
|
||||
"last_updated": "2026-04-29T00:00:00Z",
|
||||
"version": 4,
|
||||
"statements": [
|
||||
{
|
||||
"vulnerability": {
|
||||
@@ -15,106 +15,12 @@
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:oci/sencho",
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/docker/docker@v28.5.2+incompatible",
|
||||
"location": "/usr/local/lib/docker/cli-plugins/docker-compose"
|
||||
}
|
||||
]
|
||||
"@id": "pkg:golang/github.com/docker/docker@v28.5.2+incompatible"
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"impact_statement": "The authz bypass affects Docker Engine's daemon-side plugin authorization hook on oversized request bodies. docker-compose v5.1.2 statically bundles docker/docker v28.5.2+incompatible as a client-side library for API types and codecs; it never acts as a daemon and never runs authorization hooks. Sencho invokes compose only for up/down/ps operations against local user-authored compose files. The daemon authz code path is not reachable. Note on remediation: the advisory's 'fixed in 29.3.1' refers to Docker Engine the daemon product. The Go library that contains the corresponding source fix is github.com/moby/moby/v2 (a new module path adopted on the docker-29.x branch), not github.com/docker/docker which compose v5.1.2 still imports. Until upstream compose migrates to the v2 import path the v28.5.2+incompatible bundled library is the only Go-module-resolvable version, and the not_affected status is the principled triage rather than a deferred upgrade."
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://www.cve.org/CVERecord?id=CVE-2026-33747",
|
||||
"name": "CVE-2026-33747",
|
||||
"description": "BuildKit arbitrary file write via untrusted frontend"
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:oci/sencho",
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/moby/buildkit@v0.27.1",
|
||||
"location": "/usr/local/lib/docker/cli-plugins/docker-compose"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"impact_statement": "docker-compose v5.1.2 statically bundles buildkit v0.27.1. The arbitrary file write vulnerability is exploitable only when buildkit processes an attacker-controlled frontend (e.g. a malicious Dockerfile image reference). Sencho invokes compose only for up/down/ps operations against user-authored compose files. Compose does not invoke the buildkit frontend execution path in this usage."
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://www.cve.org/CVERecord?id=CVE-2026-33748",
|
||||
"name": "CVE-2026-33748",
|
||||
"description": "BuildKit Git URL fragment subdir path traversal"
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:oci/sencho",
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/moby/buildkit@v0.27.1",
|
||||
"location": "/usr/local/lib/docker/cli-plugins/docker-compose"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"impact_statement": "The Git URL fragment subdir traversal is exploitable only when buildkit fetches an attacker-controlled Git repository URL as a build context. Sencho invokes compose for up/down/ps against local user-authored compose files only. Compose does not pass Git URLs to buildkit in this usage."
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://www.cve.org/CVERecord?id=CVE-2026-24051",
|
||||
"name": "CVE-2026-24051",
|
||||
"description": "OpenTelemetry SDK PATH hijacking on process start"
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:oci/sencho",
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/go.opentelemetry.io/otel/sdk@v1.38.0",
|
||||
"location": "/usr/local/lib/docker/cli-plugins/docker-compose"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "inline_mitigations_already_exist",
|
||||
"impact_statement": "The PATH hijacking requires an attacker to control the process PATH environment variable before compose starts. The container's PATH is set to /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin at image build time. Both directories are owned by root with mode 755. Unprivileged processes cannot inject malicious binaries into these directories."
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://www.cve.org/CVERecord?id=CVE-2026-39883",
|
||||
"name": "CVE-2026-39883",
|
||||
"description": "OpenTelemetry SDK BSD kenv PATH hijacking"
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:oci/sencho",
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/go.opentelemetry.io/otel/sdk@v1.38.0",
|
||||
"location": "/usr/local/lib/docker/cli-plugins/docker-compose"
|
||||
},
|
||||
{
|
||||
"@id": "pkg:golang/go.opentelemetry.io/otel/sdk@v1.42.0",
|
||||
"location": "/usr/local/bin/docker"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_present",
|
||||
"impact_statement": "The BSD kenv PATH hijacking code path executes only on BSD operating systems (FreeBSD, OpenBSD, NetBSD). Sencho publishes linux/amd64 and linux/arm64 images only. The vulnerable code path is never executed in our runtime environment. Both the docker-compose plugin (otel/sdk v1.38.0) and the rebuilt Docker CLI binary (otel/sdk v1.42.0) bundle vulnerable versions; the same justification applies to both."
|
||||
"impact_statement": "The authorization bypass affects Docker Engine's daemon-side plugin authorization hook on oversized request bodies. docker-compose v5.1.3 statically bundles docker/docker v28.5.2+incompatible as a client-side library for API types and codecs; it never acts as a daemon and never runs authorization hooks. Sencho invokes compose only for up/down/ps operations against local user-authored compose files. The daemon auth code path is not reachable. The advisory's 'fixed in 29.3.1' refers to Docker Engine the daemon product. The Go library containing the fix is github.com/moby/moby/v2 (a new module path adopted on the docker-29.x branch), not github.com/docker/docker. Until upstream compose migrates to the v2 import path, v28.5.2+incompatible is the only Go-module-resolvable version."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user