From 907bb8f5fa1f29b22a70976e5458393b32b2d36e Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 18:42:43 +0000 Subject: [PATCH] Security: Fix potential DoS by limiting version string length Limits the length of version strings processed by `compareTo` to 256 characters. This prevents potential Denial of Service (DoS) attacks via memory exhaustion or excessive CPU usage when processing extremely long strings (e.g. 10MB+). Added regression tests in `src/security.test.ts`. --- .changeset/sentinel-dos-fix.md | 5 +++++ src/index.ts | 10 ++++++++++ src/security.test.ts | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 .changeset/sentinel-dos-fix.md diff --git a/.changeset/sentinel-dos-fix.md b/.changeset/sentinel-dos-fix.md new file mode 100644 index 00000000..59373def --- /dev/null +++ b/.changeset/sentinel-dos-fix.md @@ -0,0 +1,5 @@ +--- +"node-version": patch +--- + +Security: Fix potential DoS vulnerability by limiting maximum version string length to 256 characters. diff --git a/src/index.ts b/src/index.ts index 625ca808..297eb4dd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,6 +19,11 @@ export const EOL_DATES: Record = { "24": "2028-04-30", }; +/** + * Maximum allowed length for a version string to prevent DoS attacks. + */ +const MAX_VERSION_LENGTH = 256; + /** * Check if a major version is EOL. */ @@ -52,6 +57,11 @@ export const getVersion = (): NodeVersion => { * Compare the current node version with a target version string. */ const compareTo = (target: string): number => { + // Fail fast for excessively long strings to prevent DoS + if (target.length > MAX_VERSION_LENGTH) { + return NaN; + } + if (target !== target.trim() || target.length === 0) { return NaN; } diff --git a/src/security.test.ts b/src/security.test.ts index b5942fd7..61c4b91a 100644 --- a/src/security.test.ts +++ b/src/security.test.ts @@ -63,4 +63,36 @@ describe("security fixes", () => { const v = getVersion(); expect(v.isAtLeast("10.0.0")).toBe(true); }); + + describe("DoS prevention", () => { + test("should handle extremely long version strings gracefully", () => { + const v = getVersion(); + + // Generate a 1MB string + const hugeString = "1".repeat(1024 * 1024); + + const start = performance.now(); + const result = v.isAtLeast(hugeString); + const end = performance.now(); + + // Should return false (invalid version because it exceeds MAX_VERSION_LENGTH) + expect(result).toBe(false); + + // Should execute quickly (under 50ms implies it didn't try to parse the whole thing) + expect(end - start).toBeLessThan(100); + }); + + test("should handle huge string with many dots", () => { + const v = getVersion(); + const hugeDots = "1.".repeat(500000); // 1MB string with 500k dots + + const start = performance.now(); + const result = v.isAtLeast(hugeDots); + const end = performance.now(); + + expect(result).toBe(false); + // This is the critical check - without length limit this could be slow/OOM + expect(end - start).toBeLessThan(100); + }); + }); });