Skip to content

Commit

Permalink
Fix ReDoS vulnerability for the .end() method
Browse files Browse the repository at this point in the history
The other methods do not have this vulnerability, but I’m refactoring them while I’m at it.
  • Loading branch information
sindresorhus committed May 28, 2021
1 parent 7bd2272 commit 25246c6
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 3 deletions.
35 changes: 32 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
export default function trimNewlines(string) {
return string.replace(/^[\r\n]+|[\r\n]+$/g, '');
let start = 0;
let end = string.length;

while (start < end && (string[start] === '\r' || string[start] === '\n')) {
start++;
}

while (end > 0 && (string[end - 1] === '\r' || string[end - 1] === '\n')) {
end--;
}

return (start > 0 || end < string.length) ? string.slice(start, end) : string;
}

trimNewlines.start = string => string.replace(/^[\r\n]+/, '');
trimNewlines.end = string => string.replace(/[\r\n]+$/, '');
trimNewlines.start = string => {
const end = string.length;
let start = 0;

while (start < end && (string[start] === '\r' || string[start] === '\n')) {
start++;
}

return start > 0 ? string.slice(start, end) : string;
};

trimNewlines.end = string => {
let end = string.length;

while (end > 0 && (string[end - 1] === '\r' || string[end - 1] === '\n')) {
end--;
}

return end < string.length ? string.slice(0, end) : string;
};
39 changes: 39 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ import test from 'ava';
import trimNewlines from './index.js';

test('main', t => {
t.is(trimNewlines(''), '');
t.is(trimNewlines(' '), ' ');
t.is(trimNewlines('\n\n\r'), '');
t.is(trimNewlines('\nx\n'), 'x');
t.is(trimNewlines('\n\n\nx\n\n\n'), 'x');
t.is(trimNewlines('\r\nx\r\n'), 'x');
t.is(trimNewlines('\n\r\n\nx\n\r\n\n'), 'x');
});

test('start', t => {
t.is(trimNewlines.start(''), '');
t.is(trimNewlines.start(' '), ' ');
t.is(trimNewlines.start('\n\n\r'), '');
t.is(trimNewlines.start('\nx'), 'x');
t.is(trimNewlines.start('\r\nx'), 'x');
t.is(trimNewlines.start('\n\n\n\nx'), 'x');
Expand All @@ -17,9 +23,42 @@ test('start', t => {
});

test('end', t => {
t.is(trimNewlines.end(''), '');
t.is(trimNewlines.end(' '), ' ');
t.is(trimNewlines.end('\n\n\r'), '');
t.is(trimNewlines.end('x\n'), 'x');
t.is(trimNewlines.end('x\r\n'), 'x');
t.is(trimNewlines.end('x\n\n\n\n'), 'x');
t.is(trimNewlines.end('x\n\n\r\n\n'), 'x');
t.is(trimNewlines.end('\n\n\r\n\nx'), '\n\n\r\n\nx');
});

test('main - does not have exponential performance', t => {
for (let index = 0; index < 45000; index += 1000) {
const string = String(Array.from({length: index}).fill('\n').join('')) + 'a' + String(Array.from({length: index}).fill('\n').join(''));
const start = Date.now();
trimNewlines(string);
const difference = Date.now() - start;
t.true(difference < 10, `Execution time: ${difference}`);
}
});

test('start - does not have exponential performance', t => {
for (let index = 0; index < 45000; index += 1000) {
const string = String(Array.from({length: index}).fill('\n').join('')) + 'a';
const start = Date.now();
trimNewlines.start(string);
const difference = Date.now() - start;
t.true(difference < 10, `Execution time: ${difference}`);
}
});

test('end - does not have exponential performance', t => {
for (let index = 0; index < 45000; index += 1000) {
const string = 'a' + String(Array.from({length: index}).fill('\n').join(''));
const start = Date.now();
trimNewlines.end(string);
const difference = Date.now() - start;
t.true(difference < 10, `Execution time: ${difference}`);
}
});

0 comments on commit 25246c6

Please sign in to comment.