Added custom redirects ReDoS validation (#20515)

refs
[ENG-709](https://linear.app/tryghost/issue/ENG-709/%F0%9F%90%9B-bad-redirects-causing-container-tear-down)

Added validation to prevent RegEx's susceptible to ReDoS from being used
with custom redirects. Also moved error details out of `context` and
into `errorDetails` to be consistent with error logging elsewhere as
well as fix issue in admin-x where blank screen would be shown when an
error occurred during redirects upload (due to logic not accounting for
`context` being an object)
This commit is contained in:
Michael Barrett 2024-07-02 16:00:19 +01:00 committed by GitHub
parent a046ee324e
commit b36c2356fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 56 additions and 3 deletions

View File

@ -1,6 +1,7 @@
const _ = require('lodash');
const tpl = require('@tryghost/tpl');
const errors = require('@tryghost/errors');
const {isSafePattern} = require('redos-detector');
const messages = {
redirectsWrongFormat: 'Incorrect redirects file format.',
@ -33,18 +34,35 @@ const validate = (redirects) => {
if (!redirect.from || !redirect.to) {
throw new errors.ValidationError({
message: tpl(messages.redirectsWrongFormat),
context: redirect,
help: tpl(messages.redirectsHelp)
});
}
// Ensure valid regex
try {
// each 'from' property should be a valid RegExp string
new RegExp(redirect.from);
} catch (error) {
throw new errors.ValidationError({
message: tpl(messages.invalidRedirectsFromRegex),
context: redirect,
errorDetails: {
redirect,
invalid: true
},
help: tpl(messages.redirectsHelp)
});
}
// Ensure safe regex
const analysis = isSafePattern(redirect.from);
if (analysis.safe === false) {
throw new errors.ValidationError({
message: tpl(messages.invalidRedirectsFromRegex),
errorDetails: {
redirect,
unsafe: true,
reason: analysis.error
},
help: tpl(messages.redirectsHelp)
});
}

View File

@ -219,6 +219,7 @@
"node-jose": "2.2.0",
"path-match": "1.2.4",
"probe-image-size": "7.2.3",
"redos-detector": "5.1.0",
"rss": "1.2.2",
"sanitize-html": "2.13.0",
"semver": "7.6.2",

View File

@ -39,6 +39,26 @@ describe('UNIT: custom redirects validation', function () {
should.fail('should have thrown');
} catch (err) {
err.message.should.equal('Incorrect RegEx in redirects file.');
err.errorDetails.redirect.should.equal(config[0]);
err.errorDetails.invalid.should.be.true();
}
});
it('throws for an invalid redirects config having unsafe RegExp in from field', function () {
const config = [{
permanent: true,
from: '^\/episodes\/([a-z0-9-]+)+\/$', // Unsafe due to the surplus + at the end causing infinite backtracking
to: '/'
}];
try {
validate(config);
should.fail('should have thrown');
} catch (err) {
err.message.should.equal('Incorrect RegEx in redirects file.');
err.errorDetails.redirect.should.equal(config[0]);
err.errorDetails.unsafe.should.be.true();
err.errorDetails.reason.should.equal('hitMaxBacktracks');
}
});

View File

@ -27331,6 +27331,13 @@ redis-parser@^3.0.0:
dependencies:
redis-errors "^1.0.0"
redos-detector@5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/redos-detector/-/redos-detector-5.1.0.tgz#67660c896a48490e80b35557f876a529680f0f8d"
integrity sha512-08en/ij0//HwKZdKlelRZGQKmQhmKMQPVJPD+1THfYm64mZhLPOG0NBa47+DrOF53DyaRsCFyD7JHJaYITnt9g==
dependencies:
regjsparser "0.10.0"
reflect-metadata@0.1.14:
version "0.1.14"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.14.tgz#24cf721fe60677146bb77eeb0e1f9dece3d65859"
@ -27452,6 +27459,13 @@ regjsgen@^0.2.0:
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
integrity sha512-x+Y3yA24uF68m5GA+tBjbGYo64xXVJpbToBaWCoSNSc1hdk6dfctaRWrNFTVJZIIhL5GxW8zwjoixbnifnK59g==
regjsparser@0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.10.0.tgz#b1ed26051736b436f22fdec1c8f72635f9f44892"
integrity sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==
dependencies:
jsesc "~0.5.0"
regjsparser@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"