Table of Contents
Microsoft.OpenApi CVE-2026-49451 can terminate an in-process parser when it receives a crafted OpenAPI document with circular schema references.
If a security scanner flags Microsoft.OpenApi in a .NET 10 API, do not treat 3.x as an automatic fix. For an ASP.NET Core 10 application, the safe remediation path is to stay on the compatible 2.x line and resolve Microsoft.OpenApi to 2.7.5 or later.
This matters because CVE-2026-49451 affects Microsoft.OpenApi versions from 2.0.0-preview.11 through 2.7.4, and from 3.0.0 through 3.5.3. The first patched releases are 2.7.5 and 3.5.4. However, ASP.NET Core 10 uses OpenAPI.NET 2.x, while ASP.NET Core 11 moves to 3.x with meaningful source and binary compatibility changes. The official advisory and the ASP.NET Core 11 breaking-change note make that boundary clear.
The practical fix is:
- Find why your project resolves
Microsoft.OpenApi. - Pin a patched 2.x version for the .NET 10 application.
- Restore, build, and test the OpenAPI generation path.
- Confirm that the vulnerability report is clean.
- Prevent a future dependency update from silently changing the chosen version.
Microsoft.OpenApi CVE-2026-49451: The Real Exposure
The advisory describes an uncontrolled-recursion problem when OpenAPI.NET parses a document containing circular schema references. A crafted JSON or YAML OpenAPI document can terminate the process through stack overflow.
This is an availability problem, not remote code execution. The advisory explicitly does not claim data exposure, privilege escalation, authentication bypass, or code execution. The most relevant scenarios are services, developer tools, CLIs, or import features that parse OpenAPI documents from untrusted sources in-process.
That distinction is important. An ASP.NET Core API that only generates its own OpenAPI document is not automatically exposed to an attacker sending a malicious specification. It can still have a vulnerable transitive dependency that must be patched, but the immediate exploitability depends on whether the application parses attacker-controlled OpenAPI input.
Do not use that narrower exposure as a reason to ignore the update. Use it to set the correct urgency and to avoid writing an inaccurate security report.
Find the dependency path first
Start by finding the resolved version and the package that introduced it.
dotnet nuget why ./src/MyApi/MyApi.csproj Microsoft.OpenApi
dotnet package list \
--project ./src/MyApi/MyApi.csproj \
--include-transitive
dotnet nuget why shows the dependency graph that leads to a package. dotnet package list --include-transitive shows both direct and transitive packages. These two commands answer different questions:
- Why is
Microsoft.OpenApipresent? - Which version is NuGet actually restoring?
Do this before changing the project file. A direct reference from another library, central package management, or a stale lock file can all influence the final resolved version.
Patch .NET 10 on the compatible 2.x line
For a project that does not use Central Package Management, add a direct reference to the patched 2.x package version:
<ItemGroup>
<PackageReference Include="Microsoft.OpenApi" Version="2.7.5" />
</ItemGroup>
2.7.5 is the first patched 2.x release. If your team has already validated a later patched 2.x version, pin that approved version instead. The point is to keep the application on a patched 2.x release, not to downgrade a newer safe package accidentally.
A direct package reference is often the clearest fix because it makes the security decision visible in the project that ships the application. After the change, restore and inspect the graph again:
dotnet restore ./src/MyApi/MyApi.csproj
dotnet package list \
--project ./src/MyApi/MyApi.csproj \
--include-transitive
The output should show Microsoft.OpenApi resolving to 2.7.5 or a later 2.x version.
Use Central Package Management when the version belongs to the whole repository
If the repository uses Directory.Packages.props, keep the decision there instead of adding scattered project-level overrides.
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.OpenApi" Version="2.7.5" />
</ItemGroup>
</Project>
Transitive pinning lets Central Package Management promote a transitive dependency to the selected top-level version when needed. It is useful for security fixes, but it also means the chosen version becomes part of the repository’s compatibility contract. Test every project that uses the shared package configuration.
Do not add this property blindly to a large repository. First check whether the repository already uses Central Package Management and whether another project requires a higher compatible version.
Why upgrading to 3.x can break a .NET 10 application
The tempting fix is to point the scanner at Microsoft.OpenApi 3.5.4 and move on. That can create a different production problem.
ASP.NET Core 10 depends on OpenAPI.NET 2.x. ASP.NET Core 11 moves to OpenAPI.NET 3.x, where parts of the object model changed. Several concrete types became interfaces, OpenApiAny types were removed in favor of JsonNode values, parsing APIs changed, and reference handling was reshaped. Custom document, operation, and schema transformers may need source changes. Microsoft’s breaking-change documentation also warns that the move can affect binary compatibility.
That is why a .NET 10 security remediation should normally be:
.NET 10 application
-> patched Microsoft.OpenApi 2.x
-> restore, build, generation checks, tests
It should not be:
.NET 10 application
-> force Microsoft.OpenApi 3.x
-> discover generated-code or transformer failures later
The difference is especially important when the application uses XML documentation, custom OpenAPI transformers, or build-time OpenAPI generation. A previous ASP.NET Core issue showed a .NET 10 build failure inside generated OpenAPI source after a 3.x auto-update changed an API surface. The issue is recorded in the ASP.NET Core repository.
Verify source generation, not just restore
A successful restore proves only that NuGet selected a dependency graph. It does not prove that the generated OpenAPI code and custom transformers still compile.
Run the normal production build configuration after pinning the package:
dotnet restore ./MySolution.sln
dotnet build ./MySolution.sln \
--configuration Release \
--no-restore
dotnet test ./MySolution.sln \
--configuration Release \
--no-build
If your API generates OpenAPI documents at build time, this build is part of the verification. The .NET 10 OpenAPI tooling can generate documents during build and may use source generators to include XML documentation. The ASP.NET Core 10 release notes explain the build-time generation model and the OpenAPI.NET 2.x changes already introduced for .NET 10.
Also verify the generated document in the same way your team normally does:
- Run the integration test that requests the OpenAPI endpoint, if one exists.
- Compare the generated document against an approved snapshot or contract test.
- Check custom document, operation, and schema transformers.
- Build any client SDK generation project that consumes the document.
A package update is complete only when the dependency is patched and the API contract still builds and behaves as expected.
Make CI prove the patched state
Add the vulnerability report to the CI artifacts so the remediation remains visible.
mkdir -p artifacts
dotnet package list \
--project ./src/MyApi/MyApi.csproj \
--include-transitive \
--vulnerable \
--format json \
> artifacts/nuget-vulnerability-report.json
The report should no longer list the affected Microsoft.OpenApi version. The --format json option makes the result useful as a retained build artifact or as input to a later policy check. The official dotnet package list documentation supports combining transitive dependency information, vulnerability details, and JSON output.
If the repository uses lock files, make the restore deterministic in CI:
dotnet restore ./MySolution.sln --locked-mode
Use --locked-mode only when lock files are already part of the repository workflow. It should reinforce an existing dependency policy, not become an unrelated change in a security patch.
Do not suppress the advisory before checking the version boundary
Suppressing a vulnerability alert may be appropriate only when the scanner is demonstrably wrong about the resolved package or when the affected package cannot be reached in a specific, documented deployment. It is not a substitute for checking the dependency graph.
For this advisory, the clean path is usually available:
2.7.5or later on the 2.x line for .NET 10.3.5.4or later on the 3.x line for applications that have intentionally completed the ASP.NET Core 11 and OpenAPI.NET 3.x migration.
Treat those as two separate decisions. One is a servicing update. The other is a major-version migration.
When to move to OpenAPI.NET 3.x
Move to 3.x when the application is moving to ASP.NET Core 11 and the team is prepared to update custom OpenAPI code. Review transformers that:
- Create
OpenApiAny,OpenApiString, or related 2.x values. - Traverse schema trees or references.
- Use parsing infrastructure removed in 3.x.
- Depend on concrete model types that became interfaces.
- Are compiled into reusable libraries consumed by multiple applications.
That migration can be valuable, but it deserves its own pull request, compatibility review, and API contract checks. Do not hide it inside a CVE remediation for a .NET 10 application.
Remediation checklist
- Confirm that
Microsoft.OpenApiresolves to an affected version. - Use
dotnet nuget whyto identify the dependency path. - Pin
Microsoft.OpenApito2.7.5or later within the 2.x line for ASP.NET Core 10. - Restore and inspect the resolved dependency graph again.
- Build and test the release configuration.
- Verify OpenAPI generation and custom transformers.
- Generate a transitive vulnerability report in CI.
- Avoid forcing OpenAPI.NET 3.x unless the application is intentionally migrating to ASP.NET Core 11.
- If the product parses untrusted OpenAPI documents, consider isolating that parsing from the main application process as the advisory recommends.