VYPR
High severityOSV Advisory· Published Jan 22, 2026· Updated Feb 26, 2026

Dragonfly Manager Job API Allows Unauthenticated Access

CVE-2026-24124

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.

PackageAffected versionsPatched versions
d7y.io/dragonfly/v2Go
< 2.4.12.4.1

Affected products

2

Patches

1
9fb9a2dfde31

fix(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

News mentions

0

No linked articles in our index yet.