Skip to main content

Análise Detalhada — #07 SQL Injection

Data: 2026-07-08 Vetor: Header api-company-target


1. Fluxo do Ataque

Requisição HTTP
│ Header: api-company-target: arezzo"; DROP TABLE "Carts"; --

UserProvider.GetSchemaName() ← L64-68, sem validação
│ return "arezzo\"; DROP TABLE \"Carts\"; -- "

Repository / Query Builder
│ var query = $"SELECT * FROM \"{schema}\".\"Products\""

PostgreSQL
│ SELECT * FROM "arezzo"; DROP TABLE "Carts"; -- "."Products"

DROP TABLE executado

2. Entry Point: UserProvider.GetSchemaName()

Arquivo: coezzion-nuget-common/src/Coezzion.Common/Providers/UserProvider.cs

public string GetSchemaName()
{
var http = _context?.HttpContext;

if (http == null)
return _schemaNameScopedWrapper.SchemaName; // (A) Fallback

// (B) x-api-key venda_ai → "arezzo" (seguro, hardcoded)
var apiKeyFromHeader = http.Request.Headers["x-api-key"].ToString();
if (apiKeyFromHeader == vendaAiKeyFromConfig)
return "arezzo";

// (C) JWT claim "schema"
var schemaClaim = http.User?.FindFirst("schema");
if (schemaClaim != null && !string.IsNullOrEmpty(schemaClaim.Value))
return schemaClaim.Value; // Sem validação (fora do escopo — #30)

// (D) Header api-company-target ← VULNERÁVEL
if (http.Request.Headers.TryGetValue("api-company-target", out StringValues headerSchema)
&& headerSchema.Any())
{
return headerSchema.ToString(); // RAW — sem validação
}

// (E) Default
return _schemaNameScopedWrapper.SchemaName;
}

3. Leituras Diretas (bypass UserProvider)

3.1 Tipos de bypass

TipoPadrãoQuantidadeServiços
ADatabaseConfig.GetSchema() lê header direto8product, store, backoffice, integration, message, payments-reports, showcase, checkout
BEvent handler background5payments-reports, integration
CRepositório no construtor5showcase, payments-reports
DgRPC interceptor1product

3.2 Exemplos

Tipo A — DatabaseConfig.GetSchema():

// Product.API/Configuration/DatabaseConfig.cs:78
schemaName = contextAccessor.HttpContext.Request.Headers["api-company-target"].ToString();

Tipo B — Event handler:

// Payments.Reports.Infraestructure/EventHandlers/PaymentCreatedEventHandler.cs:22
var schema = _contextAccessor.HttpContext.Request.Headers["api-company-target"].ToString();

Tipo C — Repositório no construtor:

// ShowCase.Infrastructure/Data/Repositories/Read/UserRepository.cs:22
_schema = _contextAccessor.HttpContext?.Request.Headers["api-company-target"] ?? "arezzo";

Tipo D — gRPC:

// Product.API/gRPC/ProductAppService.cs:31
if (!context.RequestHeaders.Where(x => x.Key == "api-company-target").Any())
throw new RpcException(new Status(StatusCode.InvalidArgument, ...));

4. SQL Injection Points (por serviço)

4.1 coezzion-service-cart

Schema source: _userProvider.GetSchemaName()

ArquivoLinhasOperaçãoTabelas
ProductRepository.cs39-51, 97-100, 118-123SELECTProductsStockStores, Products
CartRepository.cs295-296, 309-310, 352-472, 536-547SELECT, UPDATECarts, CartItems, Products, Customers, Stores, CartItemRecommendations
AttendanceRepository.cs21-28, 43-50, 67-74, 97-100, 123-128SELECT, COUNTAttendances
UserReadRepository.cs50-64SELECTSellers, Stores

4.2 coezzion-service-checkout

Schema source: _userProvider.GetSchemaName()

ArquivoLinhasOperaçãoTabelas
ControlOperationRepository.cs51, 95-96UPDATE, SELECTPaymentsControlOperation, Stores
ControlOperationByStoreRepository.cs59UPDATEPaymentsControlOperationByStore
PaymentRepository.cs192-193SELECTPayments, PaymentsData
StorePagarMeRepository.cs30SELECTStorePagarMeConfig
CustomerRepository.cs46-49, 75-78SELECTCustomerOptIn, Carts, Stores
CoreSqlRepository.cs92-99, 162-163, 262-263, 324, 341, 357, 374, 393-399SELECT (multi-join)Carts, CartItems, Products, Customers, Addresses, Stores, StoresPayment, StorePaymentKeys, StoresPaymentInstallmentRules, CartItemRecommendations, CustomLink, Brands, Channels, PaymentsControlOperation, PaymentsControlOperationByStore
PaymentSqlRepository.cs30, 38, 75-96, 120-122, 169, 176SELECT (CTE)Payments, PaymentsEcomm, PaymentsData, PaymentsStatusHistory, PaymentsEcommData, PaymentsEcommStatusHistory
CartRepository.cs98-103, 322-326, 368-377, 420-421SELECT (multi-join)Carts, Stores, Customers, CartItems, Products, ProductSizes, Brands, CartItemRecommendations

4.3 coezzion-service-product

Schema source: _userProvider.GetSchemaName() (via IUserProvider)

ArquivoLinhasOperaçãoTabelas
ProductSearchQueryBuilder.cs94-166SELECT (CTE)mv_products_searchable, ProductSizes, ProductsStockStores, Products
ProductSearchWithBusinessGroupQueryBuilder.cs105-196SELECT (CTE)Mesmo
ProductSearchWithBusinessGroupQueryV2Builder.cs140-450SELECT (complex)+ Stores
ProductSearchWithBusinessGroupQueryV3Builder.cs91-242SELECT (complex)Mesmo
ProductRepository.cs343-354SELECTProducts, ProductPhotos

4.4 coezzion-service-store

Schema source: _userProvider.GetSchemaName()

ArquivoLinhasOperaçãoTabelas
StorePaymentRepository.cs284-534SELECT, UPDATE, DELETE, INSERTStores, Brands, StoresPayment, StoresPaymentInstallmentRules, StorePaymentLogs
CampaignRepository.cs78-87SELECT (func)Campaigns
StoreRepository.cs129-297SELECTStores, Brands
ChannelRepository.cs121-123SELECTStores, Channels
BrandRepository.cs160-206SELECTStores, Brands
SellerRepository.cs93-531SELECTSellers, Stores, SellersVacations, Brands
SellerVacationRepository.cs111-701SELECTSellersVacations, Stores

4.5 coezzion-service-backoffice

Schema source: _userProvider.GetSchemaName()

ArquivoLinhasOperaçãoTabelas
EntityAuditLogsRepository.cs32INSERTEntityAuditLogs
LearningVideoRepository.cs43-44SELECTLearningVideos, UserWatchedLearningVideo
ManagerIndicatorRepository.cs24-263SELECTGoals, GoalUsers, ManagerIndicators, SellerIndicators
NpsRepository.cs54-484SELECTStores, Brands
SellerIndicatorRepository.cs25-69SELECTGoals, GoalUsers, ManagerIndicators, SellerIndicators
CustomerIndicatorRepository.cs175-320SELECTCustomerIndicators, Stores, Products
OmniIndicatorsRepository.cs104SELECTOmniIndicators
StoreReadRepository.cs96-97SELECTStores, Brands
TurnListReadRepository.cs39-225SELECTStores, Brands

4.6 coezzion-service-jobs

Schema source: _userProvider.GetSchemaName()

ArquivoLinhasOperaçãoTabelas
DropperContactsDailySnapshotRepository.cs33INSERTDropperContactsDailySnapshot
CustomerIndicatorsRepository.cs35-38SELECTCustomerIndicators
PaymentRepository.cs91-92SELECTPayments, PaymentsData
SellerVacationRepository.cs23-28SELECTSellersVacations
StoreRepository.cs43-68SELECTStores
SellerRepository.cs43SELECTSellers
SellerIndicatorRepository.cs34SELECTSellerIndicators
UserRepository.cs48, 178SELECTStores, SellersVacations
CartsRepository.cs58-65, 111-112SELECTCarts, CartItems, Stores, Customers, CustomerOptIn, Brands, Products
StorePaymentsRepository.cs25-26SELECTCarts, StoresPayment

4.7 coezzion-service-payments-reports

Schema source: DIRETO do header (bypass UserProvider)

ArquivoLinhasOperaçãoTabelas
PaymentRepository.cs293-297, 322-326, 367-374, 383, 414-453, 496, 533-541, 579-611, 644-646, 677, 716-718, 769-837, 874-921SELECTPayments, PaymentsEcomm, PaymentsData, NPSReasons, NPSLink, NPSResponseReasons
StoreRepository.cs46-48SELECTStores, Channels
ControlOperationRepository.cs44-201SELECTPaymentsControlOperation, Brands, Channels, Stores, PaymentsControlOperationByStore
SalesIndicatorRepository.cs155, 194-216, 330SELECTPayments, Stores, Brands, CartItems, Carts
IntegrationRepository.cs127, 150SELECTSetaHistory, CigamHistory
CartRepository.cs248-694SELECTCarts, Stores, Brands, Customers, CartItems

4.8 coezzion-service-showcase

Schema source: DIRETO do header ou _coreOrgDbContext.CacheKey

ArquivoLinhasOperaçãoTabelas
ShowcaseTryOnLogRepository.cs27-36, 58-70SELECTShowcaseTryOnLogs
UserRepository.cs28-40, 52-60, 77-88SELECTStores

4.9 coezzion-service-integration

Schema source: DIRETO do header (via DatabaseConfig.GetSchema)

Tabelas: Integrations, PaymentTypes (via EF Core MultiTenantContextProvider).

4.10 coezzion-service-message

Schema source: DIRETO do header (via DatabaseConfig.GetSchema)


5. BFF Propagation

Arquivo: coezzion-service-bff/src/BFF.Coezzion/Application/Integration/HttpServices/HttpClientDelegatingHandlerSchema.cs

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var schemaHeader = accessor?.HttpContext?.Request.Headers["api-company-target"];
if (string.IsNullOrEmpty(schemaHeader)) return await base.SendAsync(request, cancellationToken);
request.Headers.Add("api-company-target", [schemaHeader]); // ← repassa sem validar
return await base.SendAsync(request, cancellationToken);
}

Após o fix nos downstreams, a propagação é segura — o serviço destino valida.


6. Cache Key Injection

Schema usado em chave de cache (~12 locais):

// Exemplo: CacheStoreRepositoryDecorator.cs
var cacheKey = $"{_schema}:store:{storeId}";

Schema malicioso → chave de cache arbitrária → leitura/escrita de cache de tenant errado. Risco: corrupção de cache cross-tenant.


7. CompanyTargetHeaderAttribute (Product service)

Arquivo: coezzion-service-product/src/Product.API/Filters/CompanyTargetHeaderAttribute.cs

Valida apenas presença do header (não valida valor). Popula SchemaNameScopedWrapper com valor raw:

if (context.HttpContext.Request.Headers.TryGetValue("api-company-target", out var companyTarget))
{
var wrapperSchema = context.HttpContext.RequestServices.GetService(typeof(SchemaNameScopedWrapper)) as SchemaNameScopedWrapper;
wrapperSchema.SchemaName = companyTarget.ToString(); // ← RAW
}

Este atributo é aplicado em endpoints via [CompanyTargetHeader]. Após o fix no UserProvider, o valor do SchemaNameScopedWrapper é validado no path (E) da GetSchemaName().