Skip to content

fix(readers): bound YAML anchor/alias expansion, configurable via reader settings - #3019

Draft
Vincent Biret (baywet) with Copilot wants to merge 2853 commits into
support/v1from
copilot/supportv1-port-bug-fix
Draft

fix(readers): bound YAML anchor/alias expansion, configurable via reader settings#3019
Vincent Biret (baywet) with Copilot wants to merge 2853 commits into
support/v1from
copilot/supportv1-port-bug-fix

Conversation

Copilot AI commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Pull Request

Description

Ports the billion-laughs guard from main (#3000) to the v1 reader. The v1 reader walks the SharpYaml node graph directly: aliases share a single source node, so a tiny document expands exponentially when materialized into independent IOpenApiAny trees, exhausting process memory (CWE-400). The v1 reader has a different shape from main's YamlConverter, so the fix is applied manually rather than cherry-picked, and the limits are exposed on OpenApiReaderSettings instead of a static type.

var reader = new OpenApiStringReader(new OpenApiReaderSettings
{
    MaxDepth = 128,          // default 64
    MaxNodeCount = 1_000_000 // default 5,000,000
});

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Other (please describe):

Changes Made

  • OpenApiReaderSettings: new MaxDepth / MaxNodeCount properties with DefaultMaxDepth (64, mirroring System.Text.Json) and DefaultMaxNodeCount (5,000,000); zero is rejected.
  • ParsingContext: per-parse node budget enforced in CountNode, called from the ParseNode constructor, failing with OpenApiReaderException.
  • ParseNode and subclasses: CreateAny threads a depth counter and rejects graphs nested beyond the configured depth, protecting the recursive readers from stack exhaustion.
  • OpenApiYamlDocumentReader: flows both limits from settings into every ParsingContext it creates.

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • All existing tests pass

New YamlAliasExpansionTests cover: a YAML bomb rejected during conversion and surfaced as a diagnostic error through OpenApiStringReader, excessive nesting rejected, legitimate aliases still resolving, default limit values, zero rejection, and a raised MaxDepth admitting a deeper document.

Checklist

  • My code follows the code style of this project
  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Versions applicability

See the contributing guidelines for more information about how patches are applied across multiple versions.

Additional Notes

Scope is 8 files in Microsoft.OpenApi.Readers plus one new test file. The branch content is support/v1 plus this patch; the PR base needs to be retargeted from main to support/v1 — the agent sandbox cannot set the base branch.

Vincent Biret (baywet) and others added 30 commits March 31, 2026 13:51
…n--components--Microsoft.OpenApi

chore(main): release 3.5.1
---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-version: 18.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-version: 18.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
…ft.OpenApi.Hidi.Tests/multi-4b4f90437e

Bump Microsoft.NET.Test.Sdk from 18.3.0 to 18.4.0
Fixes CSDL to OpenAPI conversion issue with binding functions to
multiple types in an inheritance tree.

Closes #2811

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fix(hidi): update Microsoft.OpenApi.OData to 3.2.1
Co-authored-by: release-please-token-provider[bot] <225477224+release-please-token-provider[bot]@users.noreply.github.com>
Bumps [dotnet-sdk](https://github.com/dotnet/sdk) from 8.0.419 to 8.0.420.
- [Release notes](https://github.com/dotnet/sdk/releases)
- [Commits](https://github.com/dotnet/sdk/commits/v8.0.420)

---
updated-dependencies:
- dependency-name: dotnet-sdk
  dependency-version: 8.0.420
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
---
updated-dependencies:
- dependency-name: Microsoft.SourceLink.GitHub
  dependency-version: 10.0.202
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
…urceLink.GitHub-10.0.202

Bump Microsoft.SourceLink.GitHub from 10.0.201 to 10.0.202
…sdk-8.0.420

chore(deps): bump dotnet-sdk from 8.0.419 to 8.0.420
Bumps Microsoft.Extensions.DependencyInjection from 10.0.5 to 10.0.6
Bumps Microsoft.Extensions.Logging from 10.0.5 to 10.0.6
Bumps Microsoft.Extensions.Logging.Abstractions from 10.0.5 to 10.0.6
Bumps Microsoft.Extensions.Logging.Console from 10.0.5 to 10.0.6
Bumps Microsoft.Extensions.Logging.Debug from 10.0.5 to 10.0.6
Bumps System.Text.Json from 10.0.5 to 10.0.6

---
updated-dependencies:
- dependency-name: Microsoft.Extensions.DependencyInjection
  dependency-version: 10.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging
  dependency-version: 10.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging
  dependency-version: 10.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging.Abstractions
  dependency-version: 10.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging.Console
  dependency-version: 10.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: System.Text.Json
  dependency-version: 10.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging.Console
  dependency-version: 10.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging.Debug
  dependency-version: 10.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging.Debug
  dependency-version: 10.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…resultsComparer/microsoftextensions-223369451a

Bump Microsoft.Extensions.DependencyInjection and 5 others
Bumps coverlet.collector from 8.0.1 to 10.0.0
Bumps coverlet.msbuild from 8.0.1 to 10.0.0

---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-version: 10.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: coverlet
- dependency-name: coverlet.collector
  dependency-version: 10.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: coverlet
- dependency-name: coverlet.msbuild
  dependency-version: 10.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: coverlet
- dependency-name: coverlet.msbuild
  dependency-version: 10.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: coverlet
...

Signed-off-by: dependabot[bot] <support@github.com>
…ft.OpenApi.Hidi.Tests/coverlet-20b9a813ee

Bump the coverlet group with 2 updates
Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 3.0.0 to 3.1.0.
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](dependabot/fetch-metadata@v3.0.0...v3.1.0)

---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
…endabot/fetch-metadata-3.1.0

chore(deps): bump dependabot/fetch-metadata from 3.0.0 to 3.1.0
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bumps [dotnet-sdk](https://github.com/dotnet/sdk) from 10.0.202 to 10.0.203.
- [Release notes](https://github.com/dotnet/sdk/releases)
- [Commits](https://github.com/dotnet/sdk/commits)

---
updated-dependencies:
- dependency-name: dotnet-sdk
  dependency-version: 10.0.203
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps Microsoft.Extensions.DependencyInjection from 10.0.6 to 10.0.7
Bumps Microsoft.Extensions.Logging from 10.0.6 to 10.0.7
Bumps Microsoft.Extensions.Logging.Abstractions from 10.0.6 to 10.0.7
Bumps Microsoft.Extensions.Logging.Console from 10.0.6 to 10.0.7
Bumps Microsoft.Extensions.Logging.Debug from 10.0.6 to 10.0.7
Bumps System.Text.Json from 10.0.6 to 10.0.7

---
updated-dependencies:
- dependency-name: Microsoft.Extensions.DependencyInjection
  dependency-version: 10.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging
  dependency-version: 10.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging
  dependency-version: 10.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging.Abstractions
  dependency-version: 10.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging.Console
  dependency-version: 10.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: System.Text.Json
  dependency-version: 10.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging.Console
  dependency-version: 10.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging.Debug
  dependency-version: 10.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
- dependency-name: Microsoft.Extensions.Logging.Debug
  dependency-version: 10.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: microsoftextensions
...

Signed-off-by: dependabot[bot] <support@github.com>
---
updated-dependencies:
- dependency-name: Microsoft.SourceLink.GitHub
  dependency-version: 10.0.203
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
…urceLink.GitHub-10.0.203

Bump Microsoft.SourceLink.GitHub from 10.0.202 to 10.0.203
…sdk-10.0.203

chore(deps): bump dotnet-sdk from 10.0.202 to 10.0.203
…resultsComparer/microsoftextensions-c2df92d560

Bump the microsoftextensions group with 6 updates
Bumps [googleapis/release-please-action](https://github.com/googleapis/release-please-action) from 4 to 5.
- [Release notes](https://github.com/googleapis/release-please-action/releases)
- [Changelog](https://github.com/googleapis/release-please-action/blob/main/CHANGELOG.md)
- [Commits](googleapis/release-please-action@v4...v5)

---
updated-dependencies:
- dependency-name: googleapis/release-please-action
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Vincent Biret (baywet) and others added 22 commits August 10, 2026 08:07
automatic promotion of shipped APIs for main
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.37.4 to 4.37.5.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@v4.37.4...v4.37.5)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.37.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
…hub/codeql-action-4.37.5

chore(deps): bump github/codeql-action from 4.37.4 to 4.37.5
#3000)

* fix: bound YAML anchor/alias expansion to prevent OOM (billion laughs)

The YAML reader converts the SharpYaml node graph - a DAG in which aliases
share a single instance - into a System.Text.Json JsonNode tree, allocating
a fresh node per path. Because JsonNode is single-parent, shared aliases must
be duplicated, so a tiny document with nested anchors/aliases expands
exponentially and exhausts process memory (CWE-400, uncontrolled resource
consumption).

Add a conversion budget to YamlConverter.ToJsonNode that caps the total
materialized node count (5,000,000) and nesting depth (64, mirroring the
System.Text.Json default already enforced on the JSON reader path). On breach
it throws OpenApiReaderException, which OpenApiYamlReader.Read converts into an
OpenApiDiagnostic error instead of allowing an OOM. Public API is unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 022bbd4f-e5e7-447a-bcdf-b2a4efaf75c3

* feat: make YAML conversion limits configurable

Expose YamlConverter.MaxDepth and MaxNodeCount as public static properties
(defaulting to DefaultMaxDepth=64 and DefaultMaxNodeCount=5,000,000) so
consumers can raise the limits for legitimately large/deep documents or lower
them to fail faster on known-small inputs, without needing a library change.
Setters validate that the value is greater than zero. Public API entries added.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 022bbd4f-e5e7-447a-bcdf-b2a4efaf75c3

* uint instead

---------

Co-authored-by: Treicy Sanchez Gutierrez (from Dev Box) <treicys@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 022bbd4f-e5e7-447a-bcdf-b2a4efaf75c3
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
Signed-off-by: Vincent Biret <vibiret@microsoft.com>
chore: upgrades dependencies not picked up by dependabot
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2e18b190-bdba-4d76-97af-b191dbd6c960
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.37.5 to 4.37.6.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@v4.37.5...v4.37.6)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.37.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* chore(main): release 3.10.0

Co-authored-by: release-please-token-provider[bot] <225477224+release-please-token-provider[bot]@users.noreply.github.com>
Co-authored-by: Gavin Barron (from Dev Box) <gavinbarron@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* ci: upgrades to code sign 6 to fix deprecation notice

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* ci: switches to net10 for hidi docker build

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* ci: passes the restore config to hidi publish for CFS

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

---------

Signed-off-by: Vincent Biret <vibiret@microsoft.com>
The agent branch was cut from main, whose reader code is unrelated to the
support/v1 reader this backport targets. Record the main-based tip as merged
while keeping the support/v1 tree so the branch can be diffed and merged
against support/v1.
Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>
…on laughs)

Ports the fix merged on main (#3000) to the support/v1 reader, which walks the
SharpYaml node graph directly. Aliases share a single source node, so a tiny
document expands exponentially when materialized into independent OpenApi any
trees, exhausting process memory (CWE-400).

Adds a per-parse node budget enforced by ParsingContext and a nesting depth
limit enforced while materializing any values. Limits are configurable through
the new OpenApiReaderLimits type and default to 5,000,000 nodes and depth 64
(mirroring the System.Text.Json default) as on main.

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>
Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>
Comment thread src/Microsoft.OpenApi.Readers/V3/OpenApiInfoDeserializer.cs Dismissed
Comment thread src/Microsoft.OpenApi.Readers/V3/OpenApiResponseDeserializer.cs Dismissed
Comment thread src/Microsoft.OpenApi.Readers/V3/OpenApiV3Deserializer.cs Dismissed
Comment thread src/Microsoft.OpenApi/Models/OpenApiReference.cs Dismissed
Comment thread src/Microsoft.OpenApi/Writers/OpenApiWriterAnyExtensions.cs Dismissed
Comment thread src/Microsoft.OpenApi/Writers/OpenApiWriterAnyExtensions.cs Dismissed
Comment thread src/Microsoft.OpenApi/Writers/OpenApiWriterAnyExtensions.cs Dismissed
Comment thread test/Microsoft.OpenApi.Readers.Tests/TestCustomExtension.cs Dismissed
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants