Dragonfly Manager Job API Allows Unauthenticated Access
Description
Dragonfly is an open source P2P-based file distribution and image acceleration system. In versions 2.4.1-rc.0 and below, the Job API endpoints (/api/v1/jobs) lack JWT authentication middleware and RBAC authorization checks in the routing configuration. This allows any unauthenticated user with access to the Manager API to view, update and delete jobs. The issue is fixed in version 2.4.1-rc.1.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Dragonfly Manager's Job API lacks authentication, allowing unauthenticated users to view, create, update, or delete jobs, risking resource exhaustion and service disruption.
Vulnerability
Overview
CVE-2026-24124 is a missing authentication vulnerability affecting the Dragonfly open-source P2P file distribution and image acceleration system. The issue resides in the Manager component's Job REST API endpoints (/api/v1/jobs). In versions up to and including v2.4.1-rc.0, these endpoints lack JWT authentication middleware and RBAC authorization checks in the routing configuration, as confirmed in the official advisory and source code [1][3].
Attack
Vector
An unauthenticated attacker with network access to the Manager API can exploit this flaw to perform arbitrary operations on jobs. Affected operations include listing all jobs (GET), creating new jobs (POST), querying job details (GET by ID), modifying jobs (PATCH), and deleting jobs (DELETE) [1]. The root cause is a missing authentication block around the Job route group in manager/router/router.go, where a TODO comment indicates the developer was aware of but had not yet addressed the gap [1]. Other API endpoints (e.g., /clusters) are correctly protected with authentication middleware [1].
Impact
Successful exploitation allows attackers to view sensitive job information, submit malicious jobs, modify existing jobs, or delete critical jobs. This could lead to resource exhaustion (e.g., by creating many jobs), information disclosure of job metadata, or service disruption (e.g., by deleting or corrupting essential jobs). No authentication or prior access is required, making the attack surface significant for any deployment exposing the Manager API [1][3].
Mitigation
The vulnerability has been patched in Dragonfly version 2.4.1-rc.1 [1][3]. The fix adds proper authentication and authorization checks to the Job API route group, aligning it with the security posture of other Manager API endpoints. Users of affected versions should upgrade immediately to the patched release [1][2].
AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
d7y.io/dragonfly/v2Go | < 2.4.1 | 2.4.1 |
Affected products
2- Range: v1.4.9-2, v2.1.0, v2.1.0-beta.1, …
- Range: <=2.4.1-rc.0
Patches
19fb9a2dfde31fix(security): Dragonfly manager job API unauthenticated access
18 files changed · +148 −67
client+1 −1 modified@@ -1 +1 @@ -Subproject commit eb476ad7a6ea0cc46d22ab9e9f830535affe32dd +Subproject commit cd2847b03aae1646d348d73533104b3b1d0196b8
deploy/helm-charts+1 −1 modified@@ -1 +1 @@ -Subproject commit a85907bf25f0cbfd93ad643ca89108d4626e05f4 +Subproject commit 957337408ee2d8e544c6e80a0bd9b5ec2ceedfc6
.github/workflows/compatibility-e2e.yml+8 −3 modified@@ -31,12 +31,12 @@ jobs: include: - module: manager image: manager - image-tag: v2.4.1-beta.1 + image-tag: v2.4.1-rc.0 chart-name: manager skip: "Rate Limit" - module: scheduler image: scheduler - image-tag: v2.4.1-beta.1 + image-tag: v2.4.1-rc.0 chart-name: scheduler skip: "Rate Limit" - module: client @@ -137,12 +137,17 @@ jobs: kind load docker-image dragonflyoss/client:latest kind load docker-image dragonflyoss/dfinit:latest + - name: Generate Dragonfly PAT + run: | + DRAGONFLY_PAT=$(uuidgen | tr -d '\n' | base64 | tr '+/' '-_' | tr -d '=') + echo "DRAGONFLY_PAT=$DRAGONFLY_PAT" >> $GITHUB_ENV + - name: Setup Helm uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 - name: Setup dragonfly run: | - helm install --wait --timeout 15m --dependency-update --create-namespace --namespace dragonfly-system --set ${{ matrix.chart-name }}.image.tag=${{ matrix.image-tag }} --set ${{ matrix.chart-name }}.image.repository=dragonflyoss/${{ matrix.image }} -f ${{ env.DRAGONFLY_CHARTS_CONFIG_PATH }} dragonfly ${{ env.DRAGONFLY_CHARTS_PATH }} + helm install --wait --timeout 15m --dependency-update --create-namespace --namespace dragonfly-system --set ${{ matrix.chart-name }}.image.tag=${{ matrix.image-tag }} --set ${{ matrix.chart-name }}.image.repository=dragonflyoss/${{ matrix.image }} --set manager.extraEnvVars[0].name=DRAGONFLY_PAT --set manager.extraEnvVars[0].value=${{ env.DRAGONFLY_PAT }} -f ${{ env.DRAGONFLY_CHARTS_CONFIG_PATH }} dragonfly ${{ env.DRAGONFLY_CHARTS_PATH }} mkdir -p /tmp/artifact/dufs && chmod 777 /tmp/artifact/dufs kubectl apply -f ${{ env.DRAGONFLY_FILE_SERVER_PATH }} kubectl wait po dufs-0 --namespace dragonfly-e2e --for=condition=ready --timeout=10m
.github/workflows/e2e-rate-limit.yml+6 −1 modified@@ -120,12 +120,17 @@ jobs: kind load docker-image dragonflyoss/client:latest kind load docker-image dragonflyoss/dfinit:latest + - name: Generate Dragonfly PAT + run: | + DRAGONFLY_PAT=$(uuidgen | tr -d '\n' | base64 | tr '+/' '-_' | tr -d '=') + echo "DRAGONFLY_PAT=$DRAGONFLY_PAT" >> $GITHUB_ENV + - name: Setup Helm uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 - name: Setup dragonfly run: | - helm install --wait --timeout 15m --dependency-update --create-namespace --namespace dragonfly-system -f ${{ matrix.charts-config }} dragonfly ${{ env.DRAGONFLY_CHARTS_PATH }} + helm install --wait --timeout 15m --dependency-update --create-namespace --namespace dragonfly-system --set manager.extraEnvVars[0].name=DRAGONFLY_PAT --set manager.extraEnvVars[0].value=${{ env.DRAGONFLY_PAT }} -f ${{ matrix.charts-config }} dragonfly ${{ env.DRAGONFLY_CHARTS_PATH }} mkdir -p /tmp/artifact/dufs && chmod 777 /tmp/artifact/dufs kubectl apply -f ${{ env.DRAGONFLY_FILE_SERVER_PATH }} kubectl wait po dufs-0 --namespace dragonfly-e2e --for=condition=ready --timeout=10m
.github/workflows/e2e.yml+6 −1 modified@@ -124,12 +124,17 @@ jobs: kind load docker-image dragonflyoss/client:latest kind load docker-image dragonflyoss/dfinit:latest + - name: Generate Dragonfly PAT + run: | + DRAGONFLY_PAT=$(uuidgen | tr -d '\n' | base64 | tr '+/' '-_' | tr -d '=') + echo "DRAGONFLY_PAT=$DRAGONFLY_PAT" >> $GITHUB_ENV + - name: Setup Helm uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 - name: Setup dragonfly run: | - helm install --wait --timeout 15m --dependency-update --create-namespace --namespace dragonfly-system -f ${{ matrix.charts-config }} dragonfly ${{ env.DRAGONFLY_CHARTS_PATH }} + helm install --wait --timeout 15m --dependency-update --create-namespace --namespace dragonfly-system --set manager.extraEnvVars[0].name=DRAGONFLY_PAT --set manager.extraEnvVars[0].value=${{ env.DRAGONFLY_PAT }} -f ${{ matrix.charts-config }} dragonfly ${{ env.DRAGONFLY_CHARTS_PATH }} mkdir -p /tmp/artifact/dufs && chmod 777 /tmp/artifact/dufs kubectl apply -f ${{ env.DRAGONFLY_FILE_SERVER_PATH }} kubectl wait po dufs-0 --namespace dragonfly-e2e --for=condition=ready --timeout=10m
manager/database/database.go+21 −0 modified@@ -20,6 +20,8 @@ import ( "encoding/json" "errors" "fmt" + "os" + "time" caches "github.com/go-gorm/caches/v4" "github.com/redis/go-redis/v9" @@ -38,6 +40,11 @@ const ( DefaultClusterName = "cluster-1" ) +const ( + // DragonflyPATEnvName is the environment variable name for generating personal access token. + DragonflyPATEnvName = "DRAGONFLY_PAT" +) + type Database struct { DB *gorm.DB RDB redis.UniversalClient @@ -230,5 +237,19 @@ func seed(db *gorm.DB) error { } } + // If DRAGONFLY_PAT is set, create a default personal access token for user ID 1(root user). + if pat := os.Getenv(DragonflyPATEnvName); pat != "" { + if err := db.Model(models.PersonalAccessToken{}).Create(&models.PersonalAccessToken{ + Name: "default", + Token: pat, + Scopes: types.DefaultPersonalAccessTokenScopes, + State: models.PersonalAccessTokenStateActive, + ExpiredAt: time.Now().AddDate(10, 0, 0), + UserID: 1, + }).Error; err != nil { + return err + } + } + return nil }
manager/router/router.go+1 −2 modified@@ -201,9 +201,8 @@ func Init(cfg *config.Config, logDir string, service service.Service, database * config.GET(":id", h.GetConfig) config.GET("", h.GetConfigs) - // TODO Add auth to the following routes and fix the tests. // Job. - job := apiv1.Group("/jobs") + job := apiv1.Group("/jobs", jwt.MiddlewareFunc(), rbac) job.POST("", middlewares.CreateJobRateLimiter(limiter), h.CreateJob) job.DELETE(":id", h.DestroyJob) job.PATCH(":id", h.UpdateJob)
manager/service/personal_access_token.go+2 −8 modified@@ -18,12 +18,10 @@ package service import ( "context" - "encoding/base64" - - "github.com/google/uuid" "d7y.io/dragonfly/v2/manager/models" "d7y.io/dragonfly/v2/manager/types" + "d7y.io/dragonfly/v2/pkg/auth" ) func (s *service) CreatePersonalAccessToken(ctx context.Context, json types.CreatePersonalAccessTokenRequest) (*models.PersonalAccessToken, error) { @@ -34,7 +32,7 @@ func (s *service) CreatePersonalAccessToken(ctx context.Context, json types.Crea personalAccessToken := models.PersonalAccessToken{ Name: json.Name, BIO: json.BIO, - Token: s.generatePersonalAccessToken(), + Token: auth.GeneratePersonalAccessToken(), Scopes: json.Scopes, State: models.PersonalAccessTokenStateActive, ExpiredAt: json.ExpiredAt, @@ -101,7 +99,3 @@ func (s *service) GetPersonalAccessTokens(ctx context.Context, q types.GetPerson return personalAccessToken, count, nil } - -func (s *service) generatePersonalAccessToken() string { - return base64.RawURLEncoding.EncodeToString([]byte(uuid.NewString())) -}
pkg/auth/personal_access_token.go+28 −0 added@@ -0,0 +1,28 @@ +/* + * Copyright 2026 The Dragonfly Authors + * + * 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 auth + +import ( + "encoding/base64" + + "github.com/google/uuid" +) + +// GeneratePersonalAccessToken generates a new personal access token. +func GeneratePersonalAccessToken() string { + return base64.RawURLEncoding.EncodeToString([]byte(uuid.NewString())) +}
test/e2e/e2e_test.go+1 −1 modified@@ -85,7 +85,6 @@ var _ = AfterSuite(func() { if err := util.GetFileServer().Purge(); err != nil { fmt.Printf("failed to purge the e2e file server: %v\n", err) } - }) var _ = BeforeSuite(func() { @@ -97,6 +96,7 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) gitCommit := strings.Fields(string(rawGitCommit))[0] fmt.Printf("git commit: %s\n", gitCommit) + // Wait for peers to start and announce to scheduler. time.Sleep(5 * time.Minute) })
test/e2e/manager/job.go+2 −2 modified@@ -41,8 +41,8 @@ func waitForDone(job *models.Job, pod *util.PodExec) bool { case <-ctx.Done(): return false case <-ticker.C: - out, err := pod.CurlCommand("", nil, nil, - fmt.Sprintf("http://dragonfly-manager.dragonfly-system.svc:8080/api/v1/jobs/%d", job.ID)).CombinedOutput() + out, err := pod.CurlCommand("", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, nil, + fmt.Sprintf("http://dragonfly-manager.dragonfly-system.svc:8080/oapi/v1/jobs/%d", job.ID)).CombinedOutput() fmt.Println(string(out)) Expect(err).NotTo(HaveOccurred()) err = json.Unmarshal(out, job)
test/e2e/manager/preheat.go+12 −12 modified@@ -62,8 +62,8 @@ var _ = Describe("Preheat with Manager", func() { }) Expect(err).NotTo(HaveOccurred()) - out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://127.0.0.1:8080/api/v1/jobs").CombinedOutput() + out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://127.0.0.1:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out)) @@ -120,8 +120,8 @@ var _ = Describe("Preheat with Manager", func() { }) Expect(err).NotTo(HaveOccurred()) - out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://dragonfly-manager.dragonfly-system.svc:8080/api/v1/jobs").CombinedOutput() + out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://dragonfly-manager.dragonfly-system.svc:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out)) @@ -178,8 +178,8 @@ var _ = Describe("Preheat with Manager", func() { }) Expect(err).NotTo(HaveOccurred()) - out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://dragonfly-manager.dragonfly-system.svc:8080/api/v1/jobs").CombinedOutput() + out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://dragonfly-manager.dragonfly-system.svc:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out)) @@ -220,8 +220,8 @@ var _ = Describe("Preheat with Manager", func() { }) Expect(err).NotTo(HaveOccurred()) - out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://dragonfly-manager.dragonfly-system.svc:8080/api/v1/jobs").CombinedOutput() + out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://dragonfly-manager.dragonfly-system.svc:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out)) @@ -274,8 +274,8 @@ var _ = Describe("Preheat with Manager", func() { }) Expect(err).NotTo(HaveOccurred()) - out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://dragonfly-manager.dragonfly-system.svc:8080/api/v1/jobs").CombinedOutput() + out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://dragonfly-manager.dragonfly-system.svc:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out)) @@ -334,8 +334,8 @@ var _ = Describe("Preheat with Manager", func() { }) Expect(err).NotTo(HaveOccurred()) - out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://dragonfly-manager.dragonfly-system.svc:8080/api/v1/jobs").CombinedOutput() + out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://dragonfly-manager.dragonfly-system.svc:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out))
test/e2e/manager/task.go+16 −16 modified@@ -63,8 +63,8 @@ var _ = Describe("GetTask and DeleteTask with Manager", func() { }) Expect(err).NotTo(HaveOccurred()) - out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://127.0.0.1:8080/api/v1/jobs").CombinedOutput() + out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://127.0.0.1:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out)) @@ -95,8 +95,8 @@ var _ = Describe("GetTask and DeleteTask with Manager", func() { }, }) Expect(err).NotTo(HaveOccurred()) - out, err = managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://127.0.0.1:8080/api/v1/jobs").CombinedOutput() + out, err = managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://127.0.0.1:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out)) @@ -117,8 +117,8 @@ var _ = Describe("GetTask and DeleteTask with Manager", func() { }, }) Expect(err).NotTo(HaveOccurred()) - out, err = managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://127.0.0.1:8080/api/v1/jobs").CombinedOutput() + out, err = managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://127.0.0.1:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out)) @@ -169,8 +169,8 @@ var _ = Describe("GetTask and DeleteTask with Manager", func() { }) Expect(err).NotTo(HaveOccurred()) - out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://127.0.0.1:8080/api/v1/jobs").CombinedOutput() + out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://127.0.0.1:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out)) @@ -201,8 +201,8 @@ var _ = Describe("GetTask and DeleteTask with Manager", func() { }, }) Expect(err).NotTo(HaveOccurred()) - out, err = managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://127.0.0.1:8080/api/v1/jobs").CombinedOutput() + out, err = managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://127.0.0.1:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out)) @@ -223,8 +223,8 @@ var _ = Describe("GetTask and DeleteTask with Manager", func() { }, }) Expect(err).NotTo(HaveOccurred()) - out, err = managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://127.0.0.1:8080/api/v1/jobs").CombinedOutput() + out, err = managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://127.0.0.1:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out)) @@ -282,8 +282,8 @@ var _ = Describe("GetTask and DeleteTask with Manager", func() { }, }) Expect(err).NotTo(HaveOccurred()) - out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://127.0.0.1:8080/api/v1/jobs").CombinedOutput() + out, err := managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://127.0.0.1:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out)) @@ -304,8 +304,8 @@ var _ = Describe("GetTask and DeleteTask with Manager", func() { }, }) Expect(err).NotTo(HaveOccurred()) - out, err = managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json"}, req, - "http://127.0.0.1:8080/api/v1/jobs").CombinedOutput() + out, err = managerPod.CurlCommand("POST", map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + util.GetPersonalAccessToken()}, req, + "http://127.0.0.1:8080/oapi/v1/jobs").CombinedOutput() fmt.Println(err) Expect(err).NotTo(HaveOccurred()) fmt.Println(string(out))
test/e2e/util/exec.go+7 −9 modified@@ -31,14 +31,14 @@ func DockerCommand(arg ...string) *exec.Cmd { container := kindDockerContainer extArgs := []string{"exec", "-i", container} extArgs = append(extArgs, arg...) - fmt.Println(fmt.Sprintf(`docker %s exec: "%s"`, container, strings.Join(arg, `" "`))) + fmt.Printf(`docker %s exec: "%s"\n`, container, strings.Join(arg, `" "`)) return exec.Command("docker", extArgs...) } func DockerCopy(dst, src string) *exec.Cmd { container := kindDockerContainer args := []string{"cp", src, fmt.Sprintf("%s:%s", container, dst)} - fmt.Println(fmt.Sprintf(`docker cp %s to %s:%s"`, src, container, dst)) + fmt.Printf(`docker cp %s to %s:%s"\n`, src, container, dst) return exec.Command("docker", args...) } @@ -49,7 +49,7 @@ func CriCtlCommand(arg ...string) *exec.Cmd { } func KubeCtlCommand(arg ...string) *exec.Cmd { - fmt.Println(fmt.Sprintf(`kubectl command: "kubectl" "%s"`, strings.Join(arg, `" "`))) + fmt.Printf(`kubectl command: "kubectl" "%s"\n`, strings.Join(arg, `" "`)) return exec.Command("kubectl", arg...) } @@ -76,9 +76,9 @@ func (p *PodExec) Command(arg ...string) *exec.Cmd { if p.container != "" { extArgs = []string{"-n", p.namespace, "exec", "-c", p.container, p.name, "--"} } - extArgs = append(extArgs, arg...) - fmt.Println(fmt.Sprintf(`pod %s/%s exec: "%s"`, p.namespace, p.name, strings.Join(arg, `" "`))) + extArgs = append(extArgs, arg...) + fmt.Printf(`pod %s/%s exec: "%s"\n`, p.namespace, p.name, strings.Join(arg, `" "`)) return KubeCtlCommand(extArgs...) } @@ -88,10 +88,8 @@ func (p *PodExec) CurlCommand(method string, header map[string]string, data map[ extArgs = append(extArgs, "-X", method) } - if header != nil { - for k, v := range header { - extArgs = append(extArgs, "-H", fmt.Sprintf("%s:%s", k, v)) - } + for k, v := range header { + extArgs = append(extArgs, "-H", fmt.Sprintf("%s:%s", k, v)) } if data != nil {
test/e2e/util/personal_access_token.go+26 −0 added@@ -0,0 +1,26 @@ +/* + * Copyright 2026 The Dragonfly Authors + * + * 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 util + +import ( + "os" +) + +// GetPersonalAccessToken gets the personal access token from the environment variable. +func GetPersonalAccessToken() string { + return os.Getenv("DRAGONFLY_PAT") +}
test/testdata/charts/config-ipv6.yaml+3 −3 modified@@ -115,7 +115,7 @@ seedClient: dynconfig: refreshInterval: 5s scheduler: - announceInterval: 10s + announceInterval: 15s log: level: debug proxy: @@ -177,9 +177,9 @@ client: host: schedulerClusterID: 1 dynconfig: - refreshInterval: 1s + refreshInterval: 5s scheduler: - announceInterval: 1s + announceInterval: 15s log: level: debug proxy:
test/testdata/charts/config-rate-limit.yaml+4 −4 modified@@ -102,9 +102,9 @@ seedClient: download: rateLimit: 1MiB dynconfig: - refreshInterval: 1s + refreshInterval: 5s scheduler: - announceInterval: 1s + announceInterval: 15s log: level: debug proxy: @@ -164,9 +164,9 @@ client: download: rateLimit: 1MiB dynconfig: - refreshInterval: 1s + refreshInterval: 5s scheduler: - announceInterval: 1s + announceInterval: 15s log: level: debug proxy:
test/testdata/charts/config.yaml+3 −3 modified@@ -111,7 +111,7 @@ seedClient: dynconfig: refreshInterval: 5s scheduler: - announceInterval: 10s + announceInterval: 15s log: level: debug proxy: @@ -171,9 +171,9 @@ client: host: schedulerClusterID: 1 dynconfig: - refreshInterval: 1s + refreshInterval: 5s scheduler: - announceInterval: 1s + announceInterval: 15s log: level: debug proxy:
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-j8hf-cp34-g4j7ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-24124ghsaADVISORY
- github.com/dragonflyoss/dragonfly/commit/9fb9a2dfde3100f32dc7f48eabee4c2b64eac55fghsax_refsource_MISCWEB
- github.com/dragonflyoss/dragonfly/security/advisories/GHSA-j8hf-cp34-g4j7ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.