Skip to content

Commit 82504b7

Browse files
authored
Fix reach template regex for timing (#371)
1 parent 4c05eee commit 82504b7

File tree

2 files changed

+25
-1
lines changed

2 files changed

+25
-1
lines changed

lib/reachTemplate.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const internals = {};
88

99
module.exports = function (obj, template, options) {
1010

11-
return template.replace(/{([^}]+)}/g, ($0, chain) => {
11+
return template.replace(/{([^{}]+)}/g, ($0, chain) => {
1212

1313
const value = Reach(obj, chain, options);
1414
return (value === undefined || value === null ? '' : value);

test/index.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2069,6 +2069,30 @@ describe('reachTemplate()', () => {
20692069

20702070
expect(Hoek.reachTemplate(obj, template, '/')).to.equal('4:9:1::');
20712071
});
2072+
2073+
it('isn\'t prone to ReDoS given an adversarial template', () => {
2074+
2075+
const sizes = [0, 1, 2, 3, 4]; // Should be evenly-spaced
2076+
const times = [];
2077+
const diffs = [];
2078+
2079+
for (const size of sizes) {
2080+
const start = Date.now();
2081+
Hoek.reachTemplate({}, '{'.repeat(size * 10000));
2082+
times.push(Date.now() - start);
2083+
}
2084+
2085+
for (let i = 1; i < times.length; ++i) {
2086+
diffs.push(times[i] - times[i - 1]);
2087+
}
2088+
2089+
// Under ReDoS, as the size of the input increases the timing accelerates upwards,
2090+
// i.e. each timing diff would be greater than the last.
2091+
2092+
const diffsMonotonic = diffs[0] < diffs[1] && diffs[1] < diffs[2] && diffs[2] < diffs[3];
2093+
2094+
expect(diffsMonotonic, 'Timing diffs monotonic').to.be.false();
2095+
});
20722096
});
20732097

20742098
describe('assert()', () => {

0 commit comments

Comments
 (0)