Skip to content

Commit 2ed5059

Browse files
committed
fix(scripts): complete regex escaping in rotateChangelog (CodeQL js/incomplete-sanitization)
The version reaching this path is semver-validated in main(), but rotateChangelog is an exported function — escape every regex metacharacter, not just dots, so a direct caller cannot smuggle a pattern into the duplicate-section check. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fc2MvWJbQ1cyNQ76ymv4hs
1 parent 1595804 commit 2ed5059

1 file changed

Lines changed: 6 additions & 1 deletion

File tree

scripts/bump.mjs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,13 @@ export function extractUnreleased(changelog) {
9898
* Moves the [Unreleased] body under "## [newVersion] - date", leaves a fresh empty
9999
* [Unreleased], and rewrites the keep-a-changelog compare links at the bottom.
100100
*/
101+
// Complete regex escape (CodeQL js/incomplete-sanitization): versions are semver-shaped
102+
// by the time main() calls this, but rotateChangelog is exported — escape EVERY
103+
// metacharacter, not just dots, so a direct caller can't smuggle a pattern in.
104+
const reEscape = (s) => String(s).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
105+
101106
export function rotateChangelog(changelog, newVersion, prevVersion, date) {
102-
if (new RegExp(`^## \\[${newVersion.replace(/\./g, "\\.")}\\]`, "m").test(changelog)) {
107+
if (new RegExp(`^## \\[${reEscape(newVersion)}\\]`, "m").test(changelog)) {
103108
throw new Error(`CHANGELOG.md already has a [${newVersion}] section`);
104109
}
105110
const body = extractUnreleased(changelog);

0 commit comments

Comments
 (0)