{"record":{"id":"03d05adb84a9a835","repo":"nopSolutions/nopCommerce","slug":"this-is-not-your-product","errorCode":null,"errorMessage":"This is not your product","messagePattern":"This is not your product","errorType":"exception","errorClass":"UnauthorizedAccessException","httpStatus":null,"severity":"error","filePath":"src/Presentation/Nop.Web/Areas/Admin/Factories/ProductModelFactory.cs","lineNumber":1738,"sourceCode":"                AvailableAttributes = await (await _specificationAttributeService.GetSpecificationAttributesWithOptionsAsync())\n                    .SelectAwait(async attributeWithOption =>\n                    {\n                        var attributeName = await GetSpecificationAttributeNameAsync(attributeWithOption);\n\n                        return new SelectListItem(attributeName, attributeWithOption.Id.ToString());\n                    }).ToListAsync(),\n                ProductId = productId,\n                Locales = await _localizedModelFactory.PrepareLocalizedModelsAsync<AddSpecificationAttributeLocalizedModel>()\n            };\n        }\n\n        var attribute = await _specificationAttributeService.GetProductSpecificationAttributeByIdAsync(specificationId.Value)\n            ?? throw new ArgumentException(\"No specification attribute found with the specified id\");\n\n        //a vendor should have access only to his products\n        var currentVendor = await _workContext.GetCurrentVendorAsync();\n        if (currentVendor != null && (await _productService.GetProductByIdAsync(attribute.ProductId)).VendorId != currentVendor.Id)\n            throw new UnauthorizedAccessException(\"This is not your product\");\n\n        var specAttributeOption = await _specificationAttributeService.GetSpecificationAttributeOptionByIdAsync(attribute.SpecificationAttributeOptionId);\n        var specAttribute = await _specificationAttributeService.GetSpecificationAttributeByIdAsync(specAttributeOption.SpecificationAttributeId);\n\n        var model = attribute.ToModel<AddSpecificationAttributeModel>();\n        model.SpecificationId = attribute.Id;\n        model.AttributeId = specAttribute.Id;\n        model.AttributeTypeName = await _localizationService.GetLocalizedEnumAsync(attribute.AttributeType);\n        model.AttributeName = specAttribute.Name;\n\n        model.AvailableAttributes = await (await _specificationAttributeService.GetSpecificationAttributesWithOptionsAsync())\n            .SelectAwait(async attributeWithOption =>\n            {\n                var attributeName = await GetSpecificationAttributeNameAsync(attributeWithOption);\n\n                return new SelectListItem(attributeName, attributeWithOption.Id.ToString());\n            })\n            .ToListAsync();","sourceCodeStart":1720,"sourceCodeEnd":1756,"githubUrl":"https://github.com/nopSolutions/nopCommerce/blob/64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2/src/Presentation/Nop.Web/Areas/Admin/Factories/ProductModelFactory.cs#L1720-L1756","documentation":"Thrown as UnauthorizedAccessException in PrepareAddSpecificationAttributeModelAsync during the vendor-scoped authorization check. If the current user is a vendor (GetCurrentVendorAsync returns non-null) and the product owning the specification attribute has a different VendorId, the vendor is attempting to access another vendor's product and access is denied. NOTE a latent bug: GetProductByIdAsync(attribute.ProductId) is not null-checked, so a missing product would throw NullReferenceException before this line — but when the product exists and belongs to another vendor, this UnauthorizedAccessException fires.","triggerScenarios":"A logged-in vendor user requests to edit a product specification attribute whose owning product's VendorId differs from the vendor's own Id. Occurs when a vendor manipulates the request id (e.g., changes specificationId in the URL) to reach another vendor's attribute, or when a product was reassigned to a different vendor after the attribute link was created.","commonSituations":"Vendor tries to edit another vendor's product spec by altering the id; product ownership transferred but old attribute links still presented; multi-vendor misconfiguration where VendorId on the product is null/0 and mismatches; testing with a vendor account against global-admin products.","solutions":["Confirm the vendor is only editing their own products; restrict the UI so vendors cannot select other vendors' specification attributes.","Ensure the product's VendorId is correctly assigned to the current vendor before exposing edit links.","If products were reassigned, re-link or migrate the specification attributes to the correct owner.","Catch UnauthorizedAccessException and return a clean 403/message instead of letting it propagate."],"exampleFix":"// before\nvar currentVendor = await _workContext.GetCurrentVendorAsync();\nif (currentVendor != null && (await _productService.GetProductByIdAsync(attribute.ProductId)).VendorId != currentVendor.Id)\n    throw new UnauthorizedAccessException(\"This is not your product\");\n// after (null-safe product load + explicit guard)\nvar currentVendor = await _workContext.GetCurrentVendorAsync();\nif (currentVendor != null)\n{\n    var ownerProduct = await _productService.GetProductByIdAsync(attribute.ProductId);\n    if (ownerProduct is null || ownerProduct.VendorId != currentVendor.Id)\n        throw new UnauthorizedAccessException(\"This is not your product\");\n}","handlingStrategy":"validation","validationCode":"// Enforce vendor ownership before exposing the editor.\nvar currentVendor = await _workContext.GetCurrentVendorAsync();\nif (currentVendor is not null)\n{\n    var ownerProduct = await _productService.GetProductByIdAsync(attribute.ProductId);\n    if (ownerProduct is null || ownerProduct.VendorId != currentVendor.Id)\n    {\n        _notificationService.ErrorNotification(\"Access denied: not your product.\");\n        return; // or 403\n    }\n}","typeGuard":"static bool VendorOwnsProduct(Vendor vendor, Product product) => vendor is not null && product is not null && product.VendorId == vendor.Id;","tryCatchPattern":"try { /* vendor-scoped load */ }\ncatch (UnauthorizedAccessException ex) { /* return 403 / forbidden view */ }","preventionTips":["Scope the vendor UI so only the vendor's own products/specs are listed.","Null-check the product before reading VendorId (current code can NullReferenceException).","When reassigning product ownership, migrate dependent specification attributes too."],"tags":["nopcommerce","admin","vendor","authorization","multi-vendor","unauthorized"],"backgroundTag":null,"analyzedSha":"64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2","analyzedAt":"2026-08-13T21:19:38.062Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}