ABP Commercial v10.0.1 guidance (practical + ABP-aligned):
Volo.Abp.Mapperly. This avoids relying on AutoMapper’s runtime recursion behavior entirely.Temporary mitigation via “global MaxDepth in ABP AutoMapper setup”:
Configure<AbpAutoMapperOptions>(...) and an AutoMapper MaxDepth hook) that I can safely recommend here.Which ABP modules/services are affected?
Volo.Abp.AutoMapper + AutoMapper profiles).Volo.Abp.AutoMapper, AddAutoMapperObjectMapper, and Profile : AutoMapper.Profile usage; those are your risk hotspots.Official patch / security timeline request (Commercial-specific):
If you want the ABP-supported replacement path (works on ABP v10):
Volo.Abp.Mapperly.AbpMapperlyModule and register Mapperly object mapper:using Volo.Abp.Modularity;
using Volo.Abp.Mapperly;
[DependsOn(typeof(AbpMapperlyModule))]
public class YourProjectApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddMapperlyObjectMapper<YourProjectApplicationModule>();
}
}
(Links you provided: only https://nvd.nist.gov/vuln/detail/CVE-2026-32933 was reachable from my URL validator; the GitHub advisory/OSV links were not reachable at validation time, so I did not rely on them here.)
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
System.IdentityModel.Tokens.Jwt to 7.5.1Microsoft.IdentityModel.* packages to 7.5.1System.IdentityModel.Tokens.Jwt 6.26.1 is to upgrade your ABP solution to a version that includes these upgraded dependencies (at least ABP 8.2+, and in practice you should move to the latest ABP version in your major line).If you’re staying on ABP 10.1.1 specifically, there is no verified ABP source stating that ABP 10.1.x supports System.IdentityModel.Tokens.Jwt 8.x via its own packages. The verified ABP guidance available shows the framework moving to 7.5.1 (not 8.x) as part of its dependency upgrades.
Links (verified):
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
_content/Volo.Abp.AspNetCore.Components.Web.LeptonXTheme/.../font-bundle.css (it comes from the NuGet package and will be regenerated/overwritten).font-bundle.css with your own file (same virtual path) so the @import url("https://fonts.googleapis.com/...") line is never shipped to the browser.MyProjectBlazorClient/wwwroot/_content/Volo.Abp.AspNetCore.Components.Web.LeptonXTheme/side-menu/css/font-bundle.css
Put your local @font-face declarations there (pointing to your local .woff2/.woff files under wwwroot/fonts/inter/...) and do not include any @import to Google Fonts.
Example skeleton (adjust paths to your real files):
/* MyProjectBlazorClient/wwwroot/_content/Volo.Abp.AspNetCore.Components.Web.LeptonXTheme/side-menu/css/font-bundle.css */
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url("/fonts/inter/Inter-VariableFont.woff2") format("woff2");
}
/* add italic, opsz variants as needed... */
MyProjectBlazorClient/wwwroot/_content/Volo.Abp.AspNetCore.Components.Web.LeptonXTheme/side-menu/css/font-bundle.rtl.css
(Usually it can be identical to font-bundle.css.)
font-bundle.css, but it will now be served from your app and will not contain the Google Fonts import, so no request to fonts.googleapis.com will be triggered.This works because ABP serves static files from your app’s wwwroot, and a file placed under the exact same _content/{packageId}/... path effectively overrides the packaged static resource at runtime.
Sources (verified)
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
/Account/ForgotPassword UI does not include a reCAPTCHA challenge by default. That’s why you can toggle it for login/registration but don’t see an option for the forgotten password page./Account/ForgotPassword (same way you customize Login/Register pages in ABP: copy the page into your host project under Pages/Account so it overrides the module page).ForgotPassword.cshtml, render your CAPTCHA widget (Google reCAPTCHA or any other).ForgotPassword.cshtml.cs, validate the CAPTCHA before calling the underlying password reset flow. If CAPTCHA fails, return the page with an error message and do not send the email.SendPasswordResetCodeAsync on AccountAppService via service replacement:[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IAccountAppService))]
public class MyAccountAppService : AccountAppService
{
public MyAccountAppService(/* same ctor deps as base */) : base(/* ... */)
{
}
public override async Task SendPasswordResetCodeAsync(SendPasswordResetCodeDto input)
{
// 1) Rate limit / throttle here (per IP/email/etc.)
// 2) Optionally perform extra checks
// 3) Then call base or replicate base logic
await base.SendPasswordResetCodeAsync(input);
}
}
Add your throttling logic before calling base.SendPasswordResetCodeAsync(input).
If you implement (1), you stop most automated attacks at the UI level. If you implement (2), you protect the system even if attackers bypass the UI and call the endpoint directly.
Links:
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
DateTime value coming from the database is UTC (which is the typical/recommended setup when AbpClockOptions.Kind = DateTimeKind.Utc), then to get it in the configured timezone (app/tenant/user via Abp.Timing.TimeZone, e.g. EST), call:var estTime = Clock.ConvertToUserTime(utcDateTime);
Example (entity loaded from DB):
var entity = await _repo.GetAsync(id);
// entity.SomeTime is assumed UTC
var estTime = Clock.ConvertToUserTime(entity.SomeTime);
Notes (important):
ConvertToUserTime(DateTime dateTime) only converts if:
AbpClockOptions.Kind = DateTimeKind.Utc so IClock.SupportsMultipleTimezone == true), anddateTime.Kind is Utc.DateTime will have Kind = Unspecified (as shown in ABP’s examples), because it represents “user/local” time without embedding timezone in DateTime.If you are using DateTimeOffset properties, you can also use:
var estTimeOffset = Clock.ConvertToUserTime(dateTimeOffset);
Sources:
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
AbpClockOptions only lets you choose the kind (Utc, Local, Unspecified). It does not support setting IClock to an arbitrary timezone like “EST”, so Clock.Now cannot be made to directly return “EST time”.AbpClockOptions.Kind = DateTimeKind.Utc (store/process in UTC).What to do instead (EST example):
Configure<AbpClockOptions>(options =>
{
options.Kind = DateTimeKind.Utc;
});
Abp.Timing.TimeZone (user/tenant/app level). Then:
Clock.ConvertToUserTime(utcDateTime) to get the time in the configured timezone.Clock.ConvertToUtc(userDateTime) when taking user input and persisting.So your code should typically look like:
var utcNow = Clock.Now; // UTC (when Kind = Utc)
var estNowForUser = Clock.ConvertToUserTime(utcNow); // converted using Abp.Timing.TimeZone
Links:
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
TenantUserSharingStrategy.Shared in ABP 10.2, the login flow is host-first (global identity is established before a tenant context is selected). As a result, tenant-specific runtime OIDC challenge configuration (Authority/ClientId/ClientSecret per tenant) is not compatible with the Shared strategy’s core flow, because the system doesn’t know the tenant at the moment it must choose the external IdP to challenge.What you can do (verified ABP-supported approaches):
Use TenantUserSharingStrategy.Isolated if you require per-tenant IdP selection at sign-in
Keep Shared, but restrict yourself to “global external IdP(s)” (host-level)
If you need tenant-specific allowed login methods (not tenant-specific OIDC credentials), customize external provider availability per tenant
ExternalProviderSettingsHelper to filter which external providers are available per tenant (e.g., TenantA sees “windows,google”, TenantB sees “google”). This can help with “mixed authentication methods across tenants” only after tenant context exists (e.g., on tenant-specific login pages or flows that resolve tenant early).ICurrentTenant to decide which providers to return.Hybrid flow (tenant selection before authentication) is not provided as a built-in mode for Shared in ABP 10.2
Isolated is usually the simpler/cleaner solution.This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
Please contact us at https://abp.io/contact to request a reset of your activated developer machines and to resolve the ABP-LIC-0012 activation issue.
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
Remove your explicit DataSeeder.SeedAsync(...) call from CreateAsync.
In ABP, tenant creation already triggers seeding via the tenant-created flow (you’re also publishing TenantCreatedEto, and your system has an event handler that seeds). Calling DataSeeder.SeedAsync in the same method guarantees a duplicate seed run and will cause slowness + “already exists” type errors.
So change your method to:
[Authorize(TenantManagementPermissions.Tenants.Create)]
public virtual async Task<TenantDto> CreateAsync(TenantCreateDto input)
{
var tenant = await TenantManager.CreateAsync(input.Name);
input.MapExtraPropertiesTo(tenant);
await TenantRepository.InsertAsync(tenant);
await CurrentUnitOfWork.SaveChangesAsync();
await DistributedEventBus.PublishAsync(
new TenantCreatedEto
{
Id = tenant.Id,
Name = tenant.Name,
Properties =
{
{ "AdminEmail", input.AdminEmailAddress },
{ "AdminPassword", input.AdminPassword }
}
});
return ObjectMapper.Map<Tenant, TenantDto>(tenant);
}
Put all tenant-initialization logic into the event handler (single place).
The event handler should:
using (CurrentTenant.Change(...)))DataSeeder.SeedAsync(new DataSeedContext(tenantId).WithProperty(...))This ensures it runs exactly once and can be executed reliably even if tenant creation happens from another service/process.
If you want it synchronous (not recommended), then don’t publish TenantCreatedEto.
That would stop the handler from running, but you lose the standard “tenant created” integration behavior. The recommended ABP approach is the opposite: keep the event, remove the manual seeding.
Links (validated):
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
iss (issuer) claim inside the access token does not match what the API expects from the discovery document / configured authority.iss.In your AuthServer project, set the issuer to your public URL (the one you want clients/APIs to accept):
using OpenIddict.Server;
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
PreConfigure<OpenIddictServerBuilder>(builder =>
{
builder.SetIssuer(new Uri(configuration["AuthServer:Authority"]!));
// Example value should be exactly the public issuer:
// https://auth-apollo-stg.ligjamaica.com/
});
}
Then make sure AuthServer:Authority is exactly the same value everywhere (AuthServer, API/HttpApiHost, Blazor app), including scheme (https) and trailing slash behavior (be consistent; OpenIddict typically returns issuer with a trailing /).
Because Cloudflare terminates TLS, your container may receive HTTP internally. Configure forwarded headers early in the pipeline (AuthServer and the API hosts) so ASP.NET Core can reconstruct the original scheme/host:
using Microsoft.AspNetCore.HttpOverrides;
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost
});
// ... the rest of your middleware pipeline
}
This helps OpenIddict generate correct endpoints/issuer when it relies on the current request.
https://auth-apollo-stg.ligjamaica.com/.well-known/openid-configuration
Confirm issuer is exactly:https://auth-apollo-stg.ligjamaica.com/iss claim matches the same value.AuthServer:Authority points to that same URL.Sources:
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.