VYPR
High severity8.5NVD Advisory· Published Mar 10, 2025· Updated Apr 15, 2026

CVE-2025-27616

CVE-2025-27616

Description

Vela is a Pipeline Automation (CI/CD) framework built on Linux container technology written in Golang. Prior to versions 0.25.3 and 0.26.3, by spoofing a webhook payload with a specific set of headers and body data, an attacker could transfer ownership of a repository and its repo level secrets to a separate repository. These secrets could be exfiltrated by follow up builds to the repository. Users with an enabled repository with access to repo level CI secrets in Vela are vulnerable to the exploit, and any user with access to the CI instance and the linked source control manager can perform the exploit. Versions 0.25.3 and 0.26.3 fix the issue. No known workarounds are available.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/go-vela/serverGo
< 0.25.30.25.3
github.com/go-vela/serverGo
>= 0.26.0, < 0.26.30.26.3

Patches

3
67c1892e2464

fix(patch): add v26.3 fixes to v25.3 patch branch (#1266)

https://github.com/go-vela/serverEaston CrupperMar 10, 2025via ghsa
3 files changed · +95 76
  • api/repo/repair.go+1 1 modified
    @@ -156,7 +156,7 @@ func RepairRepo(c *gin.Context) {
     			sourceRepo.SetPreviousName(r.GetName())
     		}
     
    -		r, err = wh.RenameRepository(ctx, h, sourceRepo, c, m)
    +		r, err = wh.RenameRepository(ctx, l, database.FromContext(c), h, sourceRepo, r, m)
     		if err != nil {
     			util.HandleError(c, http.StatusInternalServerError, err)
     			return
    
  • api/webhook/post.go+79 75 modified
    @@ -146,9 +146,72 @@ func PostWebhook(c *gin.Context) {
     	l.Debugf("hook generated from SCM: %v", h)
     	l.Debugf("repo generated from SCM: %v", r)
     
    +	// check if build was parsed from webhook.
    +	if b == nil && h.GetEvent() != constants.EventRepository {
    +		// typically, this should only happen on a webhook
    +		// "ping" which gets sent when the webhook is created
    +		c.JSON(http.StatusOK, "no build to process")
    +
    +		return
    +	}
    +
    +	// check if repo was parsed from webhook
    +	if r == nil {
    +		retErr := fmt.Errorf("%s: failed to parse repo from webhook", baseErr)
    +		util.HandleError(c, http.StatusBadRequest, retErr)
    +
    +		return
    +	}
    +
    +	var repo *types.Repo
    +
    +	if h.GetEvent() == constants.EventRepository && (h.GetEventAction() == constants.ActionRenamed || h.GetEventAction() == constants.ActionTransferred) {
    +		// get any matching hook with the repo's unique webhook ID in the SCM
    +		hook, err := database.FromContext(c).GetHookByWebhookID(ctx, h.GetWebhookID())
    +		if err != nil {
    +			retErr := fmt.Errorf("%s: failed to get hook by webhook id for %s: %w", baseErr, r.GetFullName(), err)
    +			util.HandleError(c, http.StatusBadRequest, retErr)
    +
    +			return
    +		}
    +
    +		// get the repo from the database using repo id of matching hook
    +		repo, err = database.FromContext(c).GetRepo(ctx, hook.GetRepo().GetID())
    +		if err != nil {
    +			retErr := fmt.Errorf("%s: failed to get repo by id: %w", baseErr, err)
    +			util.HandleError(c, http.StatusBadRequest, retErr)
    +
    +			return
    +		}
    +	} else {
    +		repo, err = database.FromContext(c).GetRepoForOrg(ctx, r.GetOrg(), r.GetName())
    +		if err != nil {
    +			retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err)
    +			util.HandleError(c, http.StatusBadRequest, retErr)
    +
    +			return
    +		}
    +	}
    +
    +	// verify the webhook from the source control provider using DB repo hash
    +	if c.Value("webhookvalidation").(bool) {
    +		l.WithFields(logrus.Fields{
    +			"org":  r.GetOrg(),
    +			"repo": r.GetName(),
    +		}).Tracef("verifying GitHub webhook for %s", r.GetFullName())
    +
    +		err = scm.FromContext(c).VerifyWebhook(ctx, dupRequest, repo)
    +		if err != nil {
    +			retErr := fmt.Errorf("unable to verify webhook: %w", err)
    +			util.HandleError(c, http.StatusUnauthorized, retErr)
    +
    +			return
    +		}
    +	}
    +
     	// if event is repository event, handle separately and return
     	if strings.EqualFold(h.GetEvent(), constants.EventRepository) {
    -		r, err = handleRepositoryEvent(ctx, c, m, h, r)
    +		r, err = handleRepositoryEvent(ctx, l, database.FromContext(c), m, h, r, repo)
     		if err != nil {
     			util.HandleError(c, http.StatusInternalServerError, err)
     			return
    @@ -165,29 +228,12 @@ func PostWebhook(c *gin.Context) {
     		return
     	}
     
    -	// check if build was parsed from webhook.
    -	if b == nil {
    -		// typically, this should only happen on a webhook
    -		// "ping" which gets sent when the webhook is created
    -		c.JSON(http.StatusOK, "no build to process")
    -
    -		return
    -	}
    -
     	l.Debugf(`build author: %s,
     		build branch: %s,
     		build commit: %s,
     		build ref: %s`,
     		b.GetAuthor(), b.GetBranch(), b.GetCommit(), b.GetRef())
     
    -	// check if repo was parsed from webhook
    -	if r == nil {
    -		retErr := fmt.Errorf("%s: failed to parse repo from webhook", baseErr)
    -		util.HandleError(c, http.StatusBadRequest, retErr)
    -
    -		return
    -	}
    -
     	defer func() {
     		// send API call to update the webhook
     		_, err = database.FromContext(c).UpdateHook(ctx, h)
    @@ -204,18 +250,6 @@ func PostWebhook(c *gin.Context) {
     		}).Info("hook updated")
     	}()
     
    -	// send API call to capture parsed repo from webhook
    -	repo, err := database.FromContext(c).GetRepoForOrg(ctx, r.GetOrg(), r.GetName())
    -	if err != nil {
    -		retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err)
    -		util.HandleError(c, http.StatusBadRequest, retErr)
    -
    -		h.SetStatus(constants.StatusFailure)
    -		h.SetError(retErr.Error())
    -
    -		return
    -	}
    -
     	// attach a sender SCM id if the webhook payload from the SCM has no sender id
     	// the code in ProcessWebhook implies that the sender may not always be present
     	// fallbacks like pusher/commit_author do not have an id
    @@ -319,20 +353,6 @@ func PostWebhook(c *gin.Context) {
     		"repo":    repo.GetName(),
     	}).Info("hook created")
     
    -	// verify the webhook from the source control provider
    -	if c.Value("webhookvalidation").(bool) {
    -		err = scm.FromContext(c).VerifyWebhook(ctx, dupRequest, repo)
    -		if err != nil {
    -			retErr := fmt.Errorf("unable to verify webhook: %w", err)
    -			util.HandleError(c, http.StatusUnauthorized, retErr)
    -
    -			h.SetStatus(constants.StatusFailure)
    -			h.SetError(retErr.Error())
    -
    -			return
    -		}
    -	}
    -
     	// check if the repo is active
     	if !repo.GetActive() {
     		retErr := fmt.Errorf("%s: %s is not an active repo", baseErr, repo.GetFullName())
    @@ -618,9 +638,7 @@ func PostWebhook(c *gin.Context) {
     // the database resources with any relevant changes resulting from the event, such as name changes, transfers, etc.
     //
     // the caller is responsible for returning errors to the client.
    -func handleRepositoryEvent(ctx context.Context, c *gin.Context, m *internal.Metadata, h *types.Hook, r *types.Repo) (*types.Repo, error) {
    -	l := c.MustGet("logger").(*logrus.Entry)
    -
    +func handleRepositoryEvent(ctx context.Context, l *logrus.Entry, db database.Interface, m *internal.Metadata, h *types.Hook, r *types.Repo, dbRepo *types.Repo) (*types.Repo, error) {
     	l = l.WithFields(logrus.Fields{
     		"event_type": h.GetEvent(),
     	})
    @@ -629,7 +647,7 @@ func handleRepositoryEvent(ctx context.Context, c *gin.Context, m *internal.Meta
     
     	defer func() {
     		// send API call to update the webhook
    -		hr, err := database.FromContext(c).CreateHook(ctx, h)
    +		hr, err := db.CreateHook(ctx, h)
     		if err != nil {
     			l.Errorf("unable to create webhook %s/%d: %v", r.GetFullName(), h.GetNumber(), err)
     		}
    @@ -646,7 +664,7 @@ func handleRepositoryEvent(ctx context.Context, c *gin.Context, m *internal.Meta
     	switch h.GetEventAction() {
     	// if action is renamed or transferred, go through rename routine
     	case constants.ActionRenamed, constants.ActionTransferred:
    -		r, err := RenameRepository(ctx, h, r, c, m)
    +		r, err := RenameRepository(ctx, l, db, h, r, dbRepo, m)
     		if err != nil {
     			h.SetStatus(constants.StatusFailure)
     			h.SetError(err.Error())
    @@ -659,7 +677,7 @@ func handleRepositoryEvent(ctx context.Context, c *gin.Context, m *internal.Meta
     	case "archived", "unarchived", constants.ActionEdited:
     		l.Debugf("repository action %s for %s", h.GetEventAction(), r.GetFullName())
     		// send call to get repository from database
    -		dbRepo, err := database.FromContext(c).GetRepoForOrg(ctx, r.GetOrg(), r.GetName())
    +		dbRepo, err := db.GetRepoForOrg(ctx, r.GetOrg(), r.GetName())
     		if err != nil {
     			retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err)
     
    @@ -670,7 +688,7 @@ func handleRepositoryEvent(ctx context.Context, c *gin.Context, m *internal.Meta
     		}
     
     		// send API call to capture the last hook for the repo
    -		lastHook, err := database.FromContext(c).LastHookForRepo(ctx, dbRepo)
    +		lastHook, err := db.LastHookForRepo(ctx, dbRepo)
     		if err != nil {
     			retErr := fmt.Errorf("unable to get last hook for repo %s: %w", r.GetFullName(), err)
     
    @@ -703,7 +721,7 @@ func handleRepositoryEvent(ctx context.Context, c *gin.Context, m *internal.Meta
     		}
     
     		// update repo object in the database after applying edits
    -		dbRepo, err = database.FromContext(c).UpdateRepo(ctx, dbRepo)
    +		dbRepo, err = db.UpdateRepo(ctx, dbRepo)
     		if err != nil {
     			retErr := fmt.Errorf("%s: failed to update repo %s: %w", baseErr, r.GetFullName(), err)
     
    @@ -732,32 +750,18 @@ func handleRepositoryEvent(ctx context.Context, c *gin.Context, m *internal.Meta
     // associated with that repo as well as build links for the UI.
     //
     // the caller is responsible for returning errors to the client.
    -func RenameRepository(ctx context.Context, h *types.Hook, r *types.Repo, c *gin.Context, m *internal.Metadata) (*types.Repo, error) {
    -	l := c.MustGet("logger").(*logrus.Entry)
    -
    +func RenameRepository(ctx context.Context, l *logrus.Entry, db database.Interface, h *types.Hook, r *types.Repo, dbR *types.Repo, m *internal.Metadata) (*types.Repo, error) {
     	l = l.WithFields(logrus.Fields{
     		"event_type": h.GetEvent(),
     	})
     
     	l.Debugf("renaming repository from %s to %s", r.GetPreviousName(), r.GetName())
     
    -	// get any matching hook with the repo's unique webhook ID in the SCM
    -	hook, err := database.FromContext(c).GetHookByWebhookID(ctx, h.GetWebhookID())
    -	if err != nil {
    -		return nil, fmt.Errorf("%s: failed to get hook with webhook ID %d from database", baseErr, h.GetWebhookID())
    -	}
    -
    -	// get the repo from the database using repo id of matching hook
    -	dbR, err := database.FromContext(c).GetRepo(ctx, hook.GetRepo().GetID())
    -	if err != nil {
    -		return nil, fmt.Errorf("%s: failed to get repo %d from database", baseErr, hook.GetRepo().GetID())
    -	}
    -
     	// update hook object which will be added to DB upon reaching deferred function in PostWebhook
     	h.SetRepo(r)
     
     	// send API call to capture the last hook for the repo
    -	lastHook, err := database.FromContext(c).LastHookForRepo(ctx, dbR)
    +	lastHook, err := db.LastHookForRepo(ctx, dbR)
     	if err != nil {
     		retErr := fmt.Errorf("unable to get last hook for repo %s: %w", r.GetFullName(), err)
     
    @@ -775,7 +779,7 @@ func RenameRepository(ctx context.Context, h *types.Hook, r *types.Repo, c *gin.
     	}
     
     	// get total number of secrets associated with repository
    -	t, err := database.FromContext(c).CountSecretsForRepo(ctx, dbR, map[string]interface{}{})
    +	t, err := db.CountSecretsForRepo(ctx, dbR, map[string]interface{}{})
     	if err != nil {
     		return nil, fmt.Errorf("unable to get secret count for repo %s/%s: %w", dbR.GetOrg(), dbR.GetName(), err)
     	}
    @@ -784,7 +788,7 @@ func RenameRepository(ctx context.Context, h *types.Hook, r *types.Repo, c *gin.
     	page := 1
     	// capture all secrets belonging to certain repo in database
     	for repoSecrets := int64(0); repoSecrets < t; repoSecrets += 100 {
    -		s, _, err := database.FromContext(c).ListSecretsForRepo(ctx, dbR, map[string]interface{}{}, page, 100)
    +		s, _, err := db.ListSecretsForRepo(ctx, dbR, map[string]interface{}{}, page, 100)
     		if err != nil {
     			return nil, fmt.Errorf("unable to get secret list for repo %s/%s: %w", dbR.GetOrg(), dbR.GetName(), err)
     		}
    @@ -799,7 +803,7 @@ func RenameRepository(ctx context.Context, h *types.Hook, r *types.Repo, c *gin.
     		secret.SetOrg(r.GetOrg())
     		secret.SetRepo(r.GetName())
     
    -		_, err = database.FromContext(c).UpdateSecret(ctx, secret)
    +		_, err = db.UpdateSecret(ctx, secret)
     		if err != nil {
     			return nil, fmt.Errorf("unable to update secret for repo %s/%s: %w", dbR.GetOrg(), dbR.GetName(), err)
     		}
    @@ -812,7 +816,7 @@ func RenameRepository(ctx context.Context, h *types.Hook, r *types.Repo, c *gin.
     	}
     
     	// get total number of builds associated with repository
    -	t, err = database.FromContext(c).CountBuildsForRepo(ctx, dbR, nil)
    +	t, err = db.CountBuildsForRepo(ctx, dbR, nil)
     	if err != nil {
     		return nil, fmt.Errorf("unable to get build count for repo %s: %w", dbR.GetFullName(), err)
     	}
    @@ -821,7 +825,7 @@ func RenameRepository(ctx context.Context, h *types.Hook, r *types.Repo, c *gin.
     	page = 1
     	// capture all builds belonging to repo in database
     	for build := int64(0); build < t; build += 100 {
    -		b, _, err := database.FromContext(c).ListBuildsForRepo(ctx, dbR, nil, time.Now().Unix(), 0, page, 100)
    +		b, _, err := db.ListBuildsForRepo(ctx, dbR, nil, time.Now().Unix(), 0, page, 100)
     		if err != nil {
     			return nil, fmt.Errorf("unable to get build list for repo %s: %w", dbR.GetFullName(), err)
     		}
    @@ -837,7 +841,7 @@ func RenameRepository(ctx context.Context, h *types.Hook, r *types.Repo, c *gin.
     			fmt.Sprintf("%s/%s/%d", m.Vela.WebAddress, r.GetFullName(), build.GetNumber()),
     		)
     
    -		_, err = database.FromContext(c).UpdateBuild(ctx, build)
    +		_, err = db.UpdateBuild(ctx, build)
     		if err != nil {
     			return nil, fmt.Errorf("unable to update build for repo %s: %w", dbR.GetFullName(), err)
     		}
    @@ -860,7 +864,7 @@ func RenameRepository(ctx context.Context, h *types.Hook, r *types.Repo, c *gin.
     	dbR.SetPreviousName(r.GetPreviousName())
     
     	// update the repo in the database
    -	dbR, err = database.FromContext(c).UpdateRepo(ctx, dbR)
    +	dbR, err = db.UpdateRepo(ctx, dbR)
     	if err != nil {
     		retErr := fmt.Errorf("%s: failed to update repo %s/%s", baseErr, dbR.GetOrg(), dbR.GetName())
     
    
  • scm/github/webhook.go+15 0 modified
    @@ -139,6 +139,9 @@ func (c *client) processPushEvent(ctx context.Context, h *api.Hook, payload *git
     	}).Tracef("processing push GitHub webhook for %s", payload.GetRepo().GetFullName())
     
     	repo := payload.GetRepo()
    +	if repo == nil {
    +		return &internal.Webhook{Hook: h}, nil
    +	}
     
     	// convert payload to library repo
     	r := new(api.Repo)
    @@ -268,6 +271,9 @@ func (c *client) processPREvent(h *api.Hook, payload *github.PullRequestEvent) (
     
     	// capture the repo from the payload
     	repo := payload.GetRepo()
    +	if repo == nil {
    +		return &internal.Webhook{Hook: h}, nil
    +	}
     
     	// convert payload to library repo
     	r := new(api.Repo)
    @@ -355,6 +361,9 @@ func (c *client) processDeploymentEvent(h *api.Hook, payload *github.DeploymentE
     
     	// capture the repo from the payload
     	repo := payload.GetRepo()
    +	if repo == nil {
    +		return &internal.Webhook{Hook: h}, nil
    +	}
     
     	// convert payload to library repo
     	r := new(api.Repo)
    @@ -473,6 +482,9 @@ func (c *client) processIssueCommentEvent(h *api.Hook, payload *github.IssueComm
     
     	// capture the repo from the payload
     	repo := payload.GetRepo()
    +	if repo == nil {
    +		return &internal.Webhook{Hook: h}, nil
    +	}
     
     	// convert payload to library repo
     	r := new(api.Repo)
    @@ -516,6 +528,9 @@ func (c *client) processRepositoryEvent(h *api.Hook, payload *github.RepositoryE
     	logrus.Tracef("processing repository event GitHub webhook for %s", payload.GetRepo().GetFullName())
     
     	repo := payload.GetRepo()
    +	if repo == nil {
    +		return &internal.Webhook{Hook: h}, nil
    +	}
     
     	// convert payload to library repo
     	r := new(api.Repo)
    
257886e5a3ee

fix: support list of cors origins (#1262)

https://github.com/go-vela/serverdave vaderFeb 25, 2025via ghsa
5 files changed · +125 40
  • cmd/vela-server/main.go+5 0 modified
    @@ -75,6 +75,11 @@ func main() {
     			Usage:   "web ui oauth callback path",
     			Value:   "/account/authenticate",
     		},
    +		&cli.StringSliceFlag{
    +			EnvVars: []string{"VELA_CORS_ALLOW_ORIGINS", "VELA_CORS_ALLOWED_ORIGINS"},
    +			Name:    "cors-allow-origins",
    +			Usage:   "list of origins a cross-domain request can be executed from",
    +		},
     		&cli.StringFlag{
     			EnvVars: []string{"VELA_SECRET"},
     			Name:    "vela-secret",
    
  • cmd/vela-server/metadata.go+4 0 modified
    @@ -109,6 +109,10 @@ func metadataVela(c *cli.Context) (*internal.Vela, error) {
     		vela.WebAddress = c.String("webui-addr")
     	}
     
    +	if len(c.StringSlice("cors-allow-origins")) > 0 {
    +		vela.CorsAllowOrigins = c.StringSlice("cors-allow-origins")
    +	}
    +
     	if len(c.String("webui-oauth-callback")) > 0 {
     		vela.WebOauthCallbackPath = c.String("webui-oauth-callback")
     	}
    
  • internal/metadata.go+1 0 modified
    @@ -32,6 +32,7 @@ type (
     		AccessTokenDuration  time.Duration `json:"access_token_duration"`
     		RefreshTokenDuration time.Duration `json:"refresh_token_duration"`
     		OpenIDIssuer         string        `json:"oidc_issuer"`
    +		CorsAllowOrigins     []string      `json:"cors_allow_origins"`
     	}
     
     	// Metadata is the extra set of data passed to the compiler for
    
  • router/middleware/header.go+22 4 modified
    @@ -32,8 +32,9 @@ func Options(c *gin.Context) {
     	} else {
     		c.Header("Access-Control-Allow-Origin", "*")
     
    -		if len(m.Vela.WebAddress) > 0 {
    -			c.Header("Access-Control-Allow-Origin", m.Vela.WebAddress)
    +		origin := CorsAllowOrigin(c, m)
    +		if len(origin) > 0 {
    +			c.Header("Access-Control-Allow-Origin", origin)
     			c.Header("Access-Control-Allow-Credentials", "true")
     		}
     
    @@ -65,14 +66,31 @@ func Cors(c *gin.Context) {
     
     	c.Header("Access-Control-Allow-Origin", "*")
     
    -	if len(m.Vela.WebAddress) > 0 {
    -		c.Header("Access-Control-Allow-Origin", m.Vela.WebAddress)
    +	origin := CorsAllowOrigin(c, m)
    +	if len(origin) > 0 {
    +		c.Header("Access-Control-Allow-Origin", origin)
     		c.Header("Access-Control-Allow-Credentials", "true")
     	}
     
     	c.Header("Access-Control-Expose-Headers", "link, x-total-count")
     }
     
    +// CorsAllowOrigin is a helper function that returns the
    +// allowed origin for CORS requests by checking the
    +// request origin against the allowed origins in the
    +// Vela metadata.
    +func CorsAllowOrigin(c *gin.Context, m *internal.Metadata) string {
    +	origin := c.Request.Header.Get("Origin")
    +	for _, domain := range m.Vela.CorsAllowOrigins {
    +		if domain == origin {
    +			return domain
    +		}
    +	}
    +
    +	// return the Vela web address as the default to preserve functionality
    +	return m.Vela.WebAddress
    +}
    +
     // RequestVersion is a middleware function that injects the Vela API version
     // information into the request so it will be logged. This is
     // intended for debugging and troubleshooting.
    
  • router/middleware/header_test.go+93 36 modified
    @@ -176,45 +176,102 @@ func TestMiddleware_Options_InvalidMethod(t *testing.T) {
     }
     
     func TestMiddleware_Cors(t *testing.T) {
    -	// setup types
    -	wantOrigin := "*"
    -	wantExposeHeaders := "link, x-total-count"
    -	m := &internal.Metadata{
    -		Vela: &internal.Vela{
    -			Address: "http://localhost:8080",
    +	tests := []struct {
    +		name                  string
    +		m                     *internal.Metadata
    +		origin                string
    +		expectedOrigin        string
    +		expectedCredentials   string
    +		expectedExposeHeaders string
    +	}{
    +		{
    +			name: "*",
    +			m: &internal.Metadata{
    +				Vela: &internal.Vela{
    +					Address:          "http://localhost:8080",
    +					CorsAllowOrigins: []string{},
    +				},
    +			},
    +			origin:                "http://localhost:8888",
    +			expectedOrigin:        "*",
    +			expectedCredentials:   "",
    +			expectedExposeHeaders: "link, x-total-count",
    +		},
    +		{
    +			name: "WebAddress is origin",
    +			m: &internal.Metadata{
    +				Vela: &internal.Vela{
    +					WebAddress:       "http://localhost:8888",
    +					CorsAllowOrigins: []string{},
    +				},
    +			},
    +			origin:                "http://localhost:8888",
    +			expectedOrigin:        "http://localhost:8888",
    +			expectedCredentials:   "true",
    +			expectedExposeHeaders: "link, x-total-count",
    +		},
    +		{
    +			name: "CORSAllowOrigins origin is web address",
    +			m: &internal.Metadata{
    +				Vela: &internal.Vela{
    +					WebAddress:       "http://localhost:8888",
    +					CorsAllowOrigins: []string{"http://localhost:3000", "http://localhost:3001"},
    +				},
    +			},
    +			origin:                "http://localhost:8888",
    +			expectedOrigin:        "http://localhost:8888",
    +			expectedCredentials:   "true",
    +			expectedExposeHeaders: "link, x-total-count",
    +		},
    +		{
    +			name: "CORSAllowOrigins origin is in list",
    +			m: &internal.Metadata{
    +				Vela: &internal.Vela{
    +					WebAddress:       "",
    +					CorsAllowOrigins: []string{"http://localhost:3000", "http://localhost:3001", "http://localhost:8888"},
    +				},
    +			},
    +			origin:                "http://localhost:8888",
    +			expectedOrigin:        "http://localhost:8888",
    +			expectedCredentials:   "true",
    +			expectedExposeHeaders: "link, x-total-count",
     		},
     	}
     
    -	// setup context
    -	gin.SetMode(gin.TestMode)
    -
    -	resp := httptest.NewRecorder()
    -	context, engine := gin.CreateTestContext(resp)
    -	context.Request, _ = http.NewRequest(http.MethodGet, "/health", nil)
    -
    -	// setup mock server
    -	engine.Use(Metadata(m))
    -	engine.Use(Cors)
    -	engine.GET("/health", func(c *gin.Context) {
    -		c.Status(http.StatusOK)
    -	})
    -
    -	// run test
    -	engine.ServeHTTP(context.Writer, context.Request)
    -
    -	gotOrigin := context.Writer.Header().Get("Access-Control-Allow-Origin")
    -	gotExposeHeaders := context.Writer.Header().Get("Access-Control-Expose-Headers")
    -
    -	if resp.Code != http.StatusOK {
    -		t.Errorf("CORS returned %v, want %v", resp.Code, http.StatusOK)
    -	}
    -
    -	if !reflect.DeepEqual(gotOrigin, wantOrigin) {
    -		t.Errorf("CORS Access-Control-Allow-Origin is %v, want %v", gotOrigin, wantOrigin)
    -	}
    -
    -	if !reflect.DeepEqual(gotExposeHeaders, wantExposeHeaders) {
    -		t.Errorf("CORS Access-Control-Expose-Headers is %v, want %v", gotExposeHeaders, wantExposeHeaders)
    +	for _, tt := range tests {
    +		t.Run(tt.name, func(t *testing.T) {
    +			gin.SetMode(gin.TestMode)
    +			resp := httptest.NewRecorder()
    +			context, engine := gin.CreateTestContext(resp)
    +			context.Request, _ = http.NewRequest(http.MethodGet, "/health", nil)
    +			context.Request.Header.Add("Origin", tt.origin)
    +
    +			// inject metadata
    +			engine.Use(func(c *gin.Context) {
    +				c.Set("metadata", tt.m)
    +				c.Next()
    +			})
    +			engine.Use(Cors)
    +			engine.GET("/health", func(c *gin.Context) {
    +				c.Status(http.StatusOK)
    +			})
    +			engine.ServeHTTP(context.Writer, context.Request)
    +
    +			gotOrigin := context.Writer.Header().Get("Access-Control-Allow-Origin")
    +			if gotOrigin != tt.expectedOrigin {
    +				t.Errorf("Access-Control-Allow-Origin is %v; want %v", gotOrigin, tt.expectedOrigin)
    +			}
    +
    +			gotCredentials := context.Writer.Header().Get("Access-Control-Allow-Credentials")
    +			if gotCredentials != tt.expectedCredentials {
    +				t.Errorf("Access-Control-Allow-Credentials is %v; want %v", gotCredentials, tt.expectedCredentials)
    +			}
    +
    +			gotExposeHeaders := context.Writer.Header().Get("Access-Control-Expose-Headers")
    +			if gotExposeHeaders != tt.expectedExposeHeaders {
    +				t.Errorf("Access-Control-Expose-Headers is %v; want %v", gotExposeHeaders, tt.expectedExposeHeaders)
    +			}
    +		})
     	}
     }
     
    

Vulnerability 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

8

News mentions

0

No linked articles in our index yet.