Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/sentinel_security_enhancement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"node-version": patch
---

Security: Enforce maximum version string length of 256 characters to prevent potential ReDoS/DoS vectors.
Security: Optimize version validation by replacing regex with character code checks.
18 changes: 16 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ export const EOL_DATES: Record<string, string> = {
"24": "2028-04-30",
};

/**
* Maximum allowed length for a version string.
* Prevents Denial of Service (DoS) attacks via excessively long strings.
*/
const MAX_VERSION_LENGTH = 256;

/**
* Check if a major version is EOL.
*/
Expand Down Expand Up @@ -52,6 +58,10 @@ export const getVersion = (): NodeVersion => {
* Compare the current node version with a target version string.
*/
const compareTo = (target: string): number => {
if (target.length > MAX_VERSION_LENGTH) {
return NaN;
}

if (target !== target.trim() || target.length === 0) {
return NaN;
}
Expand All @@ -65,8 +75,12 @@ export const getVersion = (): NodeVersion => {
const s2 = stripped.split(".");

for (const segment of s2) {
if (segment === "" || !/^\d+$/.test(segment)) {
return NaN;
if (segment === "") return NaN;
for (let i = 0; i < segment.length; i++) {
const code = segment.charCodeAt(i);
if (code < 48 || code > 57) {
return NaN;
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/security.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,11 @@ describe("security fixes", () => {
const v = getVersion();
expect(v.isAtLeast("10.0.0")).toBe(true);
});

test("should fail for excessively long version strings", () => {
const v = getVersion();
// 257 chars (MAX is 256)
const longString = "1".repeat(257);
expect(v.isAtLeast(longString)).toBe(false);
});
});