diff --git a/CHANGELOG.md b/CHANGELOG.md index 66b78518..22847c76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [5.2.2] - 2026-07-24 + +### Fixed +- Quote flow scalars where a colon precedes a flow indicator, #773. + +### Security +- Avoid exponential parsing time for nested flow sequence pairs. + + ## [5.2.1] - 2026-07-02 ### Fixed @@ -673,6 +682,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - First public release +[5.2.2]: https://github.com/nodeca/js-yaml/compare/5.2.1...5.2.2 [5.2.1]: https://github.com/nodeca/js-yaml/compare/5.2.0...5.2.1 [5.2.0]: https://github.com/nodeca/js-yaml/compare/5.1.0...5.2.0 [5.1.0]: https://github.com/nodeca/js-yaml/compare/5.0.0...5.1.0 diff --git a/package.json b/package.json index 8caf92af..2808f296 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "js-yaml", - "version": "5.2.1", + "version": "5.2.2", "description": "YAML 1.2 parser and serializer", "keywords": [ "yaml", diff --git a/src/parser/parser.ts b/src/parser/parser.ts index a62da765..432c22c7 100644 --- a/src/parser/parser.ts +++ b/src/parser/parser.ts @@ -148,6 +148,18 @@ function addMappingEvent ( }) } +function insertFlowPairMappingEvent (state: ParserState, snapshot: ParserSnapshot) { + state.events.splice(snapshot.eventsLength, 0, { + type: EVENT_MAPPING, + start: snapshot.position, + anchorStart: NO_RANGE, + anchorEnd: NO_RANGE, + tagStart: NO_RANGE, + tagEnd: NO_RANGE, + style: COLLECTION_STYLE_FLOW + }) +} + function addScalarEvent ( state: ParserState, valueStart: number, @@ -911,14 +923,8 @@ function readFlowCollection (state: ParserState, nodeIndent: number, props: Node state.position++ skipFlowSeparationSpace(state, nodeIndent) if (!isMapping) { - restoreState(state, entryStart) - addMappingEvent(state, entryStart.position, NO_RANGE, NO_RANGE, NO_RANGE, NO_RANGE, COLLECTION_STYLE_FLOW) - if (!parseNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true)) { - addEmptyScalarEvent(state) - } - skipFlowSeparationSpace(state, nodeIndent) - state.position++ - skipFlowSeparationSpace(state, nodeIndent) + insertFlowPairMappingEvent(state, entryStart) + if (!keyWasRead) addEmptyScalarEvent(state) } else if (!keyWasRead) { addEmptyScalarEvent(state) } @@ -933,9 +939,8 @@ function readFlowCollection (state: ParserState, nodeIndent: number, props: Node } else if (isMapping) { addEmptyScalarEvent(state) } else if (isPair) { - restoreState(state, entryStart) - addMappingEvent(state, entryStart.position, NO_RANGE, NO_RANGE, NO_RANGE, NO_RANGE, COLLECTION_STYLE_FLOW) - parseNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true) + insertFlowPairMappingEvent(state, entryStart) + if (!keyWasRead) addEmptyScalarEvent(state) addEmptyScalarEvent(state) addPopEvent(state) } diff --git a/test/core/pathological.test.mjs b/test/core/pathological.test.mjs index b697fd06..b106fe59 100644 --- a/test/core/pathological.test.mjs +++ b/test/core/pathological.test.mjs @@ -41,6 +41,14 @@ describe('Pathological tests', () => { }) }) + describe('Flow collection pairs', () => { + it('throws YAMLException on nested flow pairs without reparsing keys exponentially', () => { + assertYamlException(() => { + load('[ '.repeat(40) + '1' + ' ]: 0'.repeat(40)) + }, /object-based map does not support complex keys/) + }) + }) + describe('Merge aliases', () => { it('throws YAMLException when merge chain exceeds maxTotalMergeKeys', () => { assertYamlException(() => {