From 681add6e3d091580375fc6acc1b9d5179545ac6e Mon Sep 17 00:00:00 2001 From: Charis Vrettos Date: Wed, 20 Sep 2023 16:15:39 +0300 Subject: [PATCH] [PROD-30208] add check on s3 url for @ after domain to prevent security risks --- src/initializers/joi.ts | 3 ++- test/initializers/joi.test.ts | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/initializers/joi.ts b/src/initializers/joi.ts index 4db284cd..9ca036a5 100644 --- a/src/initializers/joi.ts +++ b/src/initializers/joi.ts @@ -190,7 +190,8 @@ const Joi: JoiWithExtensions = _Joi.extend( } ], validate(value, helpers, {bucket}) { - if (!isOwnS3Path(bucket, value)) { + const { hostname, protocol, pathname} = new URL(value); + if (!isOwnS3Path(bucket, `${protocol}//${hostname}${pathname}`)) { return helpers.error('string.notInS3'); } return value; diff --git a/test/initializers/joi.test.ts b/test/initializers/joi.test.ts index afe3b106..8411175e 100644 --- a/test/initializers/joi.test.ts +++ b/test/initializers/joi.test.ts @@ -119,8 +119,22 @@ describe('joi extensions', function () { should(underTest.error).be.undefined(); underTest.value.should.equal(url); }); + it('s3 url with @ after domain should throw error', function () { + const urls = [ + 'https://application-form.s3.amazonaws.com@malicious-url.com/tmp/123-456-789', + 'https://application-form.s3.amazonaws.com@google.com/tmp/123-456-789', + 'https://application-form.s3.amazonaws.com@joecup/tmp/123-456-789', + 'https://application-form.s3.amazonaws.com@hello', + 'https://application-form.s3.amazonaws.com@4nsex02yymx4wzjzc0ljcmsar1xsli97.oastify.com' + ]; + urls.forEach(url => { + const underTest = Joi.urlInOwnS3() + .bucket('application-form') + .validate(url); + underTest.error.message.should.equal('Invalid path provided'); + }); + }); }); - describe('url', function () { it('rejects URLs with less than two domain fragments', function () { Joi.url().validate('https://foo').error.message.should.equal('"value" must contain a valid domain name');