{"record":{"id":"9cb04fedde346187","repo":"nopSolutions/nopCommerce","slug":"card-details-not-found","errorCode":null,"errorMessage":"Card details not found","messagePattern":"Card details not found","errorType":"exception","errorClass":"NopException","httpStatus":null,"severity":"error","filePath":"src/Plugins/Nop.Plugin.Payments.PayPalCommerce/Services/PayPalCommerceServiceManager.cs","lineNumber":1641,"sourceCode":"    /// A task that represents the asynchronous operation\n    /// The task result contains the created order; error message if exists\n    /// </returns>\n    public async Task<(Order Order, string Error)> CreateOrderAsync(PayPalCommerceSettings settings,\n        ButtonPlacement placement, string paymentSource, int? cardId, bool saveCard)\n    {\n        return await HandleFunctionAsync(async () =>\n        {\n            if (!IsConfigured(settings))\n                throw new NopException(\"Plugin not configured\");\n\n            if (string.IsNullOrEmpty(settings.MerchantId))\n                throw new NopException(\"Merchant PayPal ID not set\");\n\n            var details = await PrepareCartDetailsAsync(placement);\n\n            var savedPaymentToken = await _tokenService.GetByIdAsync(cardId ?? 0);\n            if (savedPaymentToken is not null && savedPaymentToken.CustomerId != details.Customer.Id)\n                throw new NopException(\"Card details not found\");\n\n            var isGuest = await _customerService.IsGuestAsync(details.Customer);\n            var isRecurring = await _shoppingCartService.ShoppingCartIsRecurringAsync(details.Cart);\n            if (isRecurring)\n            {\n                if (!settings.UseVault)\n                    throw new NopException(\"Vault disabled\");\n\n                if (isGuest)\n                    throw new NopException(\"Anonymous checkout disabled for recurring items\");\n\n                var (error, cycleLength, cyclePeriod, totalCycles) = await _shoppingCartService.GetRecurringCycleInfoAsync(details.Cart);\n                if (!string.IsNullOrEmpty(error))\n                    throw new NopException(error);\n            }\n\n            var paymentRequest = await _orderProcessingService.GetProcessPaymentRequestAsync();\n            var (order, _) = await GetCreatedOrderAsync(settings, paymentRequest, placement, details.ShippingIsRequired, paymentSource);","sourceCodeStart":1623,"sourceCodeEnd":1659,"githubUrl":"https://github.com/nopSolutions/nopCommerce/blob/64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2/src/Plugins/Nop.Plugin.Payments.PayPalCommerce/Services/PayPalCommerceServiceManager.cs#L1623-L1659","documentation":"Thrown in CreateOrderAsync when a saved payment token (card) exists for the provided cardId but belongs to a different customer. This is a security check preventing one customer from using another's saved payment method.","triggerScenarios":"cardId is provided, _tokenService.GetByIdAsync returns a non-null token, but savedPaymentToken.CustomerId does not match details.Customer.Id.","commonSituations":"cardId was tampered with in the client request to reference another customer's card; session or authentication changed between card selection and order creation (e.g., logout/login); a bug in card selection UI passes a stale or wrong cardId; concurrent sessions under different accounts sharing a browser.","solutions":["Ensure the cardId passed to CreateOrderAsync comes from the current customer's list of saved cards only","Validate that the selected card belongs to the authenticated customer in the UI before submission","Check for authentication state changes between card selection and order creation","Audit card selection logic for any path that could pass another customer's cardId"],"exampleFix":"// before\nvar savedPaymentToken = await _tokenService.GetByIdAsync(cardId ?? 0);\nif (savedPaymentToken is not null && savedPaymentToken.CustomerId != details.Customer.Id)\n    throw new NopException(\"Card details not found\");\n\n// after\nvar savedPaymentToken = cardId.HasValue\n    ? (await _tokenService.GetByCustomerIdAsync(details.Customer.Id))\n        .FirstOrDefault(t => t.Id == cardId.Value)\n    : null;\n// Token is already scoped to the customer — no cross-customer access possible","handlingStrategy":"validation","validationCode":"// Scope card lookup to the current customer to prevent cross-customer access\nif (cardId.HasValue)\n{\n    var customerTokens = await _tokenService.GetByCustomerIdAsync(details.Customer.Id);\n    var validToken = customerTokens.FirstOrDefault(t => t.Id == cardId.Value);\n    if (validToken is null)\n        return Error(\"Selected card not found\");\n}","typeGuard":"static bool TokenBelongsToCustomer(PaymentToken token, int customerId)\n    => token is not null && token.CustomerId == customerId;","tryCatchPattern":"var (order, error) = await manager.CreateOrderAsync(settings, placement, paymentSource, cardId, saveCard);\nif (!string.IsNullOrEmpty(error) && error == \"Card details not found\")\n    return BadRequest(\"Invalid card selection\");","preventionTips":["Only populate card selection UI with the current customer's own saved cards","Validate cardId ownership on the server before submitting the order","Treat cross-customer card access attempts as potential security incidents"],"tags":["security","saved-cards","payment-token","customer-data","paypal-commerce","nopcommerce"],"backgroundTag":null,"analyzedSha":"64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2","analyzedAt":"2026-08-13T21:19:38.062Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}