From 7ce9d8cbbafb9420078ca1555b907bce62aea367 Mon Sep 17 00:00:00 2001 From: gagik Date: Mon, 17 Nov 2025 13:13:36 +0100 Subject: [PATCH 1/4] chore(mongodb-redact): redact special character cases for password MONGOSH-2991 --- packages/mongodb-redact/src/secrets.spec.ts | 53 +++++++++++++++++++++ packages/mongodb-redact/src/secrets.ts | 5 +- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/packages/mongodb-redact/src/secrets.spec.ts b/packages/mongodb-redact/src/secrets.spec.ts index 3af8b617..07599a42 100644 --- a/packages/mongodb-redact/src/secrets.spec.ts +++ b/packages/mongodb-redact/src/secrets.spec.ts @@ -93,4 +93,57 @@ describe('dictionary-based secret redaction', function () { usr: '', }); }); + + describe('special characters in passwords', function () { + it('redacts passwords at start, end, or entire string', function () { + expect( + redact('!start is pwd', [{ value: '!start', kind: 'password' }]), + ).to.equal(' is pwd'); + + expect( + redact('pwd is end!', [{ value: 'end!', kind: 'password' }]), + ).to.equal('pwd is '); + + expect( + redact('The password is !@#$%', [{ value: '!@#$%', kind: 'password' }]), + ).to.equal('The password is '); + }); + + it('redacts a special-character only connection string', function () { + const secret = '!#!!'; + const content = 'Connection string: mongodb://user:!#!!@localhost:27017/'; + + const redacted = redact(content, [{ value: secret, kind: 'password' }]); + + expect(redacted).to.equal( + 'Connection string: @localhost:27017/', + ); + }); + + for (const { char, password } of [ + { char: '.', password: 'test.pass' }, + { char: '*', password: 'test*pass' }, + { char: '+', password: 'test+pass' }, + { char: '?', password: 'test?pass' }, + { char: '[', password: 'test[123]' }, + { char: '(', password: 'test(abc)' }, + { char: '|', password: 'test|pass' }, + { char: '\\', password: 'test\\pass' }, + { char: '^', password: '^test123' }, + { char: '$', password: 'test$123' }, + { char: '@', password: 'user@123' }, + { char: '#', password: 'pass#word' }, + { char: '%', password: 'test%20' }, + { char: '&', password: 'rock&roll' }, + { char: 'լավ', password: 'լավ' }, + ]) { + it(`redacts passwords with ${char}`, function () { + const content = `pwd: ${password} end`; + const redacted = redact(content, [ + { value: password, kind: 'password' }, + ]); + expect(redacted).to.equal('pwd: end'); + }); + } + }); }); diff --git a/packages/mongodb-redact/src/secrets.ts b/packages/mongodb-redact/src/secrets.ts index 4c0a519e..fe4aa6b8 100644 --- a/packages/mongodb-redact/src/secrets.ts +++ b/packages/mongodb-redact/src/secrets.ts @@ -32,7 +32,10 @@ export function redactSecretsOnString( ); } - const regex = new RegExp(`\\b${escape(value)}\\b`, 'g'); + // Escape the value for use in regex and use negative lookahead/lookbehind + // to match secrets not surrounded by word characters + const escapedValue = escape(value); + const regex = new RegExp(`(?`) as T; } From f2c9beab8350adda8ed1eabda612fb790310ec68 Mon Sep 17 00:00:00 2001 From: gagik Date: Tue, 18 Nov 2025 11:34:35 +0100 Subject: [PATCH 2/4] chore: redact MongoDB URIs better --- packages/mongodb-redact/.vscode/settings.json | 15 ++++ packages/mongodb-redact/src/index.spec.ts | 83 +++++++++++++++++-- packages/mongodb-redact/src/regexes.ts | 12 +-- packages/mongodb-redact/src/secrets.spec.ts | 6 +- 4 files changed, 99 insertions(+), 17 deletions(-) create mode 100644 packages/mongodb-redact/.vscode/settings.json diff --git a/packages/mongodb-redact/.vscode/settings.json b/packages/mongodb-redact/.vscode/settings.json new file mode 100644 index 00000000..4a402fc6 --- /dev/null +++ b/packages/mongodb-redact/.vscode/settings.json @@ -0,0 +1,15 @@ +{ + "mochaExplorer.files": "{src,lib}/**/*.spec.ts", + "mochaExplorer.require": [ + "../../scripts/import-expansions.js", + "ts-node/register" + ], + "mochaExplorer.timeout": 60000, + "mochaExplorer.ui": "bdd", + "mochaExplorer.monkeyPatch": true, + "mochaExplorer.autoload": true, + "testExplorer.codeLens": true, + "testExplorer.gutterDecoration": true, + "testExplorer.onStart": "reset", + "testExplorer.onReload": "reset" +} diff --git a/packages/mongodb-redact/src/index.spec.ts b/packages/mongodb-redact/src/index.spec.ts index ca48dbdd..02566a5f 100644 --- a/packages/mongodb-redact/src/index.spec.ts +++ b/packages/mongodb-redact/src/index.spec.ts @@ -161,13 +161,82 @@ describe('mongodb-redact', function () { expect(res).to.equal(''); }); - it('should redact MongoDB connection URIs', function () { - let res = redact( - 'mongodb://db1.example.net,db2.example.net:2500/?replicaSet=test&connectTimeoutMS=300000', - ); - expect(res).to.equal(''); - res = redact('mongodb://localhost,localhost:27018,localhost:27019'); - expect(res).to.equal(''); + describe('MongoDB connection strings', function () { + it('should redact MongoDB connection URIs', function () { + let res = redact( + 'mongodb://db1.example.net,db2.example.net:2500/?replicaSet=test&connectTimeoutMS=300000', + ); + expect(res).to.equal(''); + res = redact('mongodb://localhost,localhost:27018,localhost:27019'); + expect(res).to.equal(''); + }); + + it('should redact MongoDB URIs with credentials', function () { + let res = redact('mongodb://user:password@localhost:27017/admin'); + expect(res).to.equal(''); + res = redact('mongodb://admin:secret123@db.example.com/mydb'); + expect(res).to.equal(''); + }); + + it('should redact MongoDB URIs with special characters in usernames and passwords', function () { + let res = redact('mongodb://user:p%40ss!word@localhost:27017/'); + expect(res).to.equal(''); + res = redact('mongodb://ad!min:te%st#123$@db.example.com:27017/'); + expect(res).to.equal(''); + res = redact('mongodb://!user:my%20pass@localhost/mydb'); + expect(res).to.equal(''); + res = redact( + 'mongodb://user:p&ssw!rd#123@host.com:27017/db?authSource=admin', + ); + expect(res).to.equal(''); + }); + + it('should redact MongoDB SRV URIs', function () { + let res = redact( + 'mongodb+srv://user:password@cluster0.example.com/test', + ); + expect(res).to.equal(''); + res = redact( + 'mongodb+srv://admin:secret@mycluster.mongodb.net/mydb?retryWrites=true', + ); + expect(res).to.equal(''); + }); + + it('should redact MongoDB URIs with query parameters', function () { + let res = redact( + 'mongodb://localhost:27017/mydb?ssl=true&replicaSet=rs0', + ); + expect(res).to.equal(''); + res = redact( + 'mongodb://user:pass@host.com/db?authSource=admin&readPreference=primary', + ); + expect(res).to.equal(''); + }); + + it('should redact MongoDB URIs with replica sets', function () { + let res = redact( + 'mongodb://host1:27017,host2:27017,host3:27017/?replicaSet=myReplSet', + ); + expect(res).to.equal(''); + res = redact('mongodb://user:pass@host1,host2,host3/db?replicaSet=rs0'); + expect(res).to.equal(''); + }); + + it('should redact MongoDB URIs with IP addresses', function () { + let res = redact('mongodb://192.168.1.100:27017/mydb'); + expect(res).to.equal(''); + res = redact('mongodb://user:password@10.0.0.5:27017/admin'); + expect(res).to.equal(''); + }); + + it('should redact simple MongoDB URIs', function () { + let res = redact('mongodb://localhost'); + expect(res).to.equal(''); + res = redact('mongodb://localhost:27017'); + expect(res).to.equal(''); + res = redact('mongodb://localhost/mydb'); + expect(res).to.equal(''); + }); }); it('should redact general linux/unix user paths', function () { diff --git a/packages/mongodb-redact/src/regexes.ts b/packages/mongodb-redact/src/regexes.ts index c4abff94..f6d08bd8 100644 --- a/packages/mongodb-redact/src/regexes.ts +++ b/packages/mongodb-redact/src/regexes.ts @@ -27,6 +27,12 @@ export const regexes = [ '$1$6', ], + // MongoDB connection strings (before IP addresses to handle mongodb://IP:port URIs) + [ + /(mongodb(?:\+srv)?:\/\/)(www\.)?(?:[^:/@\s]+:[^@\s]*@)?[-a-zA-Z0-9@:%._+~#=,]{2,256}(\.[a-z]{2,6})?\b([-a-zA-Z0-9@:%_+.~#?&/=]*)/gim, + '', + ], + // IP addresses [ /((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])/gm, @@ -39,12 +45,6 @@ export const regexes = [ '', ], - // MongoDB connection strings - [ - /(mongodb:\/\/)(www\.)?[-a-zA-Z0-9@:%._+~#=,]{2,256}(\.[a-z]{2,6})?\b([-a-zA-Z0-9@:%_+.~#?&/=]*)/gim, - '', - ], - // Compass Schema URL fragments [/#schema\/\w+\.\w+/, '#schema/'], ] as const; diff --git a/packages/mongodb-redact/src/secrets.spec.ts b/packages/mongodb-redact/src/secrets.spec.ts index 07599a42..ed2ae16e 100644 --- a/packages/mongodb-redact/src/secrets.spec.ts +++ b/packages/mongodb-redact/src/secrets.spec.ts @@ -111,13 +111,11 @@ describe('dictionary-based secret redaction', function () { it('redacts a special-character only connection string', function () { const secret = '!#!!'; - const content = 'Connection string: mongodb://user:!#!!@localhost:27017/'; + const content = 'Connection string: mongodb://!!!#:!#!!@localhost:27017/'; const redacted = redact(content, [{ value: secret, kind: 'password' }]); - expect(redacted).to.equal( - 'Connection string: @localhost:27017/', - ); + expect(redacted).to.equal('Connection string: '); }); for (const { char, password } of [ From 93b40a8eeb08535499c27a0355df276533ce5f90 Mon Sep 17 00:00:00 2001 From: Gagik Amaryan Date: Tue, 18 Nov 2025 12:21:58 +0100 Subject: [PATCH 3/4] Delete packages/mongodb-redact/.vscode/settings.json --- packages/mongodb-redact/.vscode/settings.json | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 packages/mongodb-redact/.vscode/settings.json diff --git a/packages/mongodb-redact/.vscode/settings.json b/packages/mongodb-redact/.vscode/settings.json deleted file mode 100644 index 4a402fc6..00000000 --- a/packages/mongodb-redact/.vscode/settings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "mochaExplorer.files": "{src,lib}/**/*.spec.ts", - "mochaExplorer.require": [ - "../../scripts/import-expansions.js", - "ts-node/register" - ], - "mochaExplorer.timeout": 60000, - "mochaExplorer.ui": "bdd", - "mochaExplorer.monkeyPatch": true, - "mochaExplorer.autoload": true, - "testExplorer.codeLens": true, - "testExplorer.gutterDecoration": true, - "testExplorer.onStart": "reset", - "testExplorer.onReload": "reset" -} From dbeffe03a2607c7dc417a095457a38a4344dfbe6 Mon Sep 17 00:00:00 2001 From: gagik Date: Tue, 18 Nov 2025 13:20:29 +0100 Subject: [PATCH 4/4] chore: liberal regex --- packages/mongodb-redact/src/regexes.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/mongodb-redact/src/regexes.ts b/packages/mongodb-redact/src/regexes.ts index f6d08bd8..3266c7a2 100644 --- a/packages/mongodb-redact/src/regexes.ts +++ b/packages/mongodb-redact/src/regexes.ts @@ -27,11 +27,8 @@ export const regexes = [ '$1$6', ], - // MongoDB connection strings (before IP addresses to handle mongodb://IP:port URIs) - [ - /(mongodb(?:\+srv)?:\/\/)(www\.)?(?:[^:/@\s]+:[^@\s]*@)?[-a-zA-Z0-9@:%._+~#=,]{2,256}(\.[a-z]{2,6})?\b([-a-zA-Z0-9@:%_+.~#?&/=]*)/gim, - '', - ], + // MongoDB connection strings + [/mongodb(?:\+srv)?:\/\/\S+/gim, ''], // IP addresses [