fix(api): PostTemplatesTags queries database and begins transaction before team ownership check (tag enumeration oracle)
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 76/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Tranquilo
- Stack tecnológico
- go, postgres
Línea de trabajo
Comienza en packages/api/internal/handlers/template_tags.go, en PostTemplatesTags, y compara el orden de autorización con GetTemplatesTemplateIDTags y DeleteTemplatesTags. Después, inspecciona o añade el caso específico en packages/api/internal/handlers/template_tags_test.go y ejecuta las pruebas de API relevantes. Se considera terminado cuando las solicitudes no autorizadas devuelven 403 de forma coherente sin consultar el tag ni iniciar una transacción.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Problem
In POST /templates/tags (packages/api/internal/handlers/template_tags.go), the control plane handler initiates a database transaction via a.sqlcDB.WithTx(ctx) and executes client.GetTemplateWithBuildByTag before validating whether the authenticated user's team owns the requested template (if aliasInfo.TeamID != team.ID).
This ordering defect causes two distinct issues:
-
Tag Enumeration / Information Disclosure Oracle:
When a user sendsPOST /templates/tagstargeting a template owned by a different team:- If the requested
tagdoes not exist on that template:GetTemplateWithBuildByTagreturnssql.ErrNoRows, which triggersErrTemplateNotFound, responding with404 Not Found("Template '<target>' with tag '<tag>' not found"). - If the requested
tagexists on that template: the query succeeds, and only afterwards at line 115 isaliasInfo.TeamID != team.IDchecked, responding with403 Forbidden("You don't have access to sandbox template '%s'").
An unauthorized tenant can therefore determine whether arbitrary private build tags (e.g.,staging,v2.0.0-rc1,hotfix) exist on other teams' templates by probing the endpoint and observing the difference between HTTP404and HTTP403.
- If the requested
-
Unnecessary Database Load and Transaction Allocation:
Every unauthorized or invalid tag request against another tenant's template allocates a Postgres transaction connection from the pool (WithTx), acquires read locks, executes queries, and then rolls back upon failure.
Root Cause
In packages/api/internal/handlers/template_tags.go:L75-L122, tag resolution and database transaction creation precede the team ownership authorization check:
// Current flow in template_tags.go:
aliasInfo, err := a.templateCache.ResolveAlias(ctx, templateID)
if err != nil { ... }
// BUG: Transaction started and DB queried BEFORE checking aliasInfo.TeamID == team.ID
txErr := a.sqlcDB.WithTx(ctx).Exec(func(queries *queries.Queries) error {
build, err := queries.GetTemplateWithBuildByTag(ctx, ...)
if err != nil {
return ErrTemplateNotFound // Returns 404 to unauthorized caller if tag missing
}
...
if aliasInfo.TeamID != team.ID {
return a.sendAPIStoreError(c, http.StatusForbidden, ...) // Returns 403 only if tag exists
}
})
In contrast, peer handlers such as DeleteTemplatesTags (template_tags.go:L139) and GetTemplatesTemplateIDTags (template_tags.go:L21) enforce if aliasInfo.TeamID != team.ID immediately after alias resolution:
| Handler | Authorization Check Timing | Tag Enumeration Vulnerable? |
|---|---|---|
GET /templates/{templateID}/tags |
Immediate after ResolveAlias |
No |
DELETE /templates/tags |
Immediate after ResolveAlias |
No |
POST /templates/tags (Current) |
Deferred after GetTemplateWithBuildByTag DB query |
Yes (404 vs 403 Oracle) |
POST /templates/tags (Expected) |
Immediate after ResolveAlias |
No (403 Forbidden) |
Reproduction Steps
- Create a template
template-Aunderteam-1with tagv1.0.0. - Authenticate as an unrelated user
team-2. - Send
POST /templates/tagstargetingtemplate-Awithtag: "v9.9.9"(non-existent).- Observed:
HTTP 404 Not Found({"code": 404, "message": "Template 'template-A' with tag 'v9.9.9' not found"})
- Observed:
- Send
POST /templates/tagstargetingtemplate-Awithtag: "v1.0.0"(existing tag).- Observed:
HTTP 403 Forbidden({"code": 403, "message": "You don't have access to sandbox template 'template-A'"})
- Observed:
- Expected: Both requests must return
HTTP 403 Forbiddenwithout leaking metadata about tag existence.
Technical Context
- File affected:
packages/api/internal/handlers/template_tags.go - Subsystem: Control Plane API / Templates & Tags
- Impact: Medium (Security/Privacy: cross-tenant metadata disclosure & unnecessary database transaction overhead)
Proposed Changes
| # | Change | File(s) Affected | Complexity |
|---|---|---|---|
| 1 | Move if aliasInfo.TeamID != team.ID check immediately after ResolveAlias before WithTx |
packages/api/internal/handlers/template_tags.go |
Trivial |
| 2 | Add unit test TestPostTemplatesTags_RejectsOtherTeamTemplate verifying 403 Forbidden |
packages/api/internal/handlers/template_tags_test.go |
Low |
- Lenguaje dominante
- Go
- Estrellas
- 1.6k
- Forks
- 438
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de e2b-dev/runtime
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
-
sandbox cache: StartRemoving state transition not broadcast, all allocations see stale Running state Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 86/100
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 86/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 86/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
Todos los issues de e2b-dev/runtime
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 84/100
-
enhancement needs triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
-
kind/cleanup
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
kubernetes-sigs/kueue#15947 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
sympozium-ai/sympozium#627 ·