Skip to content

fix(api): enforce team ownership check before tag resolution in PostTemplatesTags - #3574

Open
chill-czar wants to merge 1 commit into
e2b-dev:mainfrom
chill-czar:fix/template-tags-auth-check
Open

fix(api): enforce team ownership check before tag resolution in PostTemplatesTags#3574
chill-czar wants to merge 1 commit into
e2b-dev:mainfrom
chill-czar:fix/template-tags-auth-check

Conversation

@chill-czar

@chill-czar chill-czar commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Closes #3573

Summary

  • Move the aliasInfo.TeamID != team.ID team ownership authorization check in PostTemplatesTags immediately after a.templateCache.ResolveAlias, before opening database transactions or executing queries.GetTemplateWithBuildByTag.
  • Eliminate cross-tenant tag enumeration oracle where unauthorized callers could determine if private build tags exist by comparing 404 Not Found vs 403 Forbidden responses.
  • Prevent unauthenticated/unauthorized callers from allocating Postgres database transactions (WithTx) on unowned templates.
  • Add unit test TestPostTemplatesTags_RejectsOtherTeamTemplate asserting 403 Forbidden early.

Why

In packages/api/internal/handlers/template_tags.go, PostTemplatesTags previously executed queries.GetTemplateWithBuildByTag inside a database transaction before checking team ownership. If a tag was not present on an unowned template, the handler returned 404 from the query error before reaching the 403 authorization check at line 115. Moving the check immediately after ResolveAlias matches the structure in DeleteTemplatesTags and GetTemplatesTemplateIDTags, preventing metadata leakage and saving database transaction overhead.

Diff Overview

 	aliasInfo, err := a.templateCache.ResolveAlias(ctx, templateID)
 	if err != nil {
 		a.sendAPIStoreError(c, http.StatusNotFound, fmt.Sprintf("Template '%s' not found: %s", templateID, err))
 		return
 	}
 
+	if aliasInfo.TeamID != team.ID {
+		a.sendAPIStoreError(c, http.StatusForbidden, fmt.Sprintf("You don't have access to sandbox template '%s'", templateID))
+		return
+	}
+
 	txErr := a.sqlcDB.WithTx(ctx).Exec(func(queries *queries.Queries) error {
 		build, err := queries.GetTemplateWithBuildByTag(ctx, queries.GetTemplateWithBuildByTagParams{
 			TemplateID: aliasInfo.TemplateID,
 			Tag:        &tag,
 		})

Test Plan

  • Unit test: go test -v ./packages/api/internal/handlers -run TestPostTemplatesTags_RejectsOtherTeamTemplate
  • Package test suite passes: go test -v ./packages/api/internal/handlers/...
  • Linter & Formatter pass: make fmt and make lint
  • Confirmed unauthorized callers receive 403 Forbidden regardless of whether the tag exists or does not exist

/cc @jakubno @dobrac @ValentaTomas @arkamar @tvi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(api): PostTemplatesTags queries database and begins transaction before team ownership check (tag enumeration oracle)

1 participant