From 02584cec9d94e599bdf39c4339cbfcec5c1651cd Mon Sep 17 00:00:00 2001
From: rcmadhankumar <madhankumar.chellamuthu@suse.com>
Date: Wed, 22 Apr 2026 11:31:55 +0530
Subject: [PATCH 2/2] CVE-2026-33747: Fix: executor: validate container IDs
 centrally --

CVE-2026-33747

BuildKit is a toolkit for converting source code to build artifacts
in an efficient, expressive and repeatable manner. Prior to version
0.28.1, when using a custom BuildKit frontend, the frontend can
craft an API message that causes files to be written outside of the
BuildKit state directory for the execution context. The issue has
been fixed in v0.28.1. The vulnerability requires using an untrusted
BuildKit frontend set with `#syntax` or `--build-arg BUILDKIT_SYNTAX`.
Using these options with a well-known frontend image like
`docker/dockerfile` is not affected.

Fix:

executor: validate container IDs centrally
Add executor.ValidContainerID and enforce it in runc/containerd
Run paths.

Only runc executor used the ID in filesystem operations.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit 789df2422341960b7549d14ea475add43e73cd74)
(cherry picked from commit 5e285127899ea49bad2437f2d53114bbe30dd36f)

Reference: https://github.com/moby/buildkit/commit/099cf80f5ebc935c48d2925499bffe703a54cff4

Fixes CVE-2026-33747
Fixes bsc#1260967
---
 .../executor/containerdexecutor/executor.go   |  3 ++
 .../moby/buildkit/executor/containerid.go     | 18 ++++++++++
 .../buildkit/executor/containerid_test.go     | 33 +++++++++++++++++++
 .../executor/runcexecutor/executor.go         | 10 ++++--
 4 files changed, 61 insertions(+), 3 deletions(-)
 create mode 100644 vendor/github.com/moby/buildkit/executor/containerid.go
 create mode 100644 vendor/github.com/moby/buildkit/executor/containerid_test.go

diff --git a/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor.go b/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor.go
index ac195c4315..f5aa152c20 100644
--- a/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor.go
+++ b/vendor/github.com/moby/buildkit/executor/containerdexecutor/executor.go
@@ -82,6 +82,9 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.M
 	if id == "" {
 		id = identity.NewID()
 	}
+	if err := executor.ValidContainerID(id); err != nil {
+		return err
+	}
 
 	startedOnce := sync.Once{}
 	done := make(chan error, 1)
diff --git a/vendor/github.com/moby/buildkit/executor/containerid.go b/vendor/github.com/moby/buildkit/executor/containerid.go
new file mode 100644
index 0000000000..421c8ad4eb
--- /dev/null
+++ b/vendor/github.com/moby/buildkit/executor/containerid.go
@@ -0,0 +1,18 @@
+package executor
+
+import "github.com/pkg/errors"
+
+// ValidContainerID validates that id is non-empty and contains only ASCII letters and digits.
+func ValidContainerID(id string) error {
+	if id == "" {
+		return errors.New("container id must not be empty")
+	}
+	for i := 0; i < len(id); i++ {
+		ch := id[i]
+		if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') {
+			continue
+		}
+		return errors.Errorf("invalid container id %q: only letters and numbers are allowed", id)
+	}
+	return nil
+}
diff --git a/vendor/github.com/moby/buildkit/executor/containerid_test.go b/vendor/github.com/moby/buildkit/executor/containerid_test.go
new file mode 100644
index 0000000000..8912238d20
--- /dev/null
+++ b/vendor/github.com/moby/buildkit/executor/containerid_test.go
@@ -0,0 +1,33 @@
+package executor
+
+import "testing"
+
+func TestValidContainerID(t *testing.T) {
+	t.Parallel()
+
+	tests := []struct {
+		name    string
+		id      string
+		wantErr bool
+	}{
+		{name: "lowercase", id: "abc123", wantErr: false},
+		{name: "uppercase", id: "AbC123", wantErr: false},
+		{name: "empty", id: "", wantErr: true},
+		{name: "dash", id: "abc-123", wantErr: true},
+		{name: "slash", id: "abc/123", wantErr: true},
+		{name: "underscore", id: "abc_123", wantErr: true},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+			err := ValidContainerID(tc.id)
+			if tc.wantErr && err == nil {
+				t.Fatalf("expected an error for id %q", tc.id)
+			}
+			if !tc.wantErr && err != nil {
+				t.Fatalf("expected no error for id %q, got %v", tc.id, err)
+			}
+		})
+	}
+}
diff --git a/vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go b/vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go
index 213ebb7366..5a318abf72 100644
--- a/vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go
+++ b/vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go
@@ -140,6 +140,13 @@ func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Ex
 }
 
 func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount, mounts []executor.Mount, process executor.ProcessInfo, started chan<- struct{}) (err error) {
+	if id == "" {
+		id = identity.NewID()
+	}
+	if err := executor.ValidContainerID(id); err != nil {
+		return err
+	}
+
 	meta := process.Meta
 
 	startedOnce := sync.Once{}
@@ -200,9 +207,6 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
 		defer release()
 	}
 
-	if id == "" {
-		id = identity.NewID()
-	}
 	bundle := filepath.Join(w.root, id)
 
 	if err := os.Mkdir(bundle, 0711); err != nil {
-- 
2.54.0

