Skip to content

Commit b7f469d

Browse files
committed
fix(pg-connection-string): prototype pollution via query strings
1 parent c78b302 commit b7f469d

File tree

3 files changed

+44
-10
lines changed

3 files changed

+44
-10
lines changed

packages/pg-connection-string/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ function parse(str, options = {}) {
1414

1515
// Check for empty host in URL
1616

17-
const config = {}
17+
const config = Object.create(null)
1818
let result
1919
let dummyHost = false
2020
if (/ |%[^a-f0-9]|%[a-f0-9][^a-f0-9]/i.test(str)) {
@@ -164,7 +164,7 @@ function toConnectionOptions(sslConfig) {
164164
}
165165

166166
return c
167-
}, {})
167+
}, Object.create(null))
168168

169169
return connectionOptions
170170
}
@@ -200,7 +200,7 @@ function toClientConfig(config) {
200200
}
201201

202202
return c
203-
}, {})
203+
}, Object.create(null))
204204

205205
return poolConfig
206206
}

packages/pg-connection-string/test/clientConfig.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ describe('toClientConfig', function () {
4646
const config = parse('pg:///?sslmode=no-verify')
4747
const clientConfig = toClientConfig(config)
4848

49-
clientConfig.ssl?.should.deep.equal({
49+
expect(clientConfig.ssl).to.deep.equal({
5050
rejectUnauthorized: false,
5151
})
5252
})
@@ -55,14 +55,14 @@ describe('toClientConfig', function () {
5555
const config = parse('pg:///?sslmode=verify-ca')
5656
const clientConfig = toClientConfig(config)
5757

58-
clientConfig.ssl?.should.deep.equal({})
58+
expect(clientConfig.ssl).to.deep.equal({})
5959
})
6060

6161
it('converts other sslmode options', function () {
6262
const config = parse('pg:///?sslmode=verify-ca')
6363
const clientConfig = toClientConfig(config)
6464

65-
clientConfig.ssl?.should.deep.equal({})
65+
expect(clientConfig.ssl).to.deep.equal({})
6666
})
6767

6868
it('converts ssl cert options', function () {
@@ -77,7 +77,7 @@ describe('toClientConfig', function () {
7777
const config = parse(connectionString)
7878
const clientConfig = toClientConfig(config)
7979

80-
clientConfig.ssl?.should.deep.equal({
80+
expect(clientConfig.ssl).to.deep.equal({
8181
ca: 'example ca\n',
8282
cert: 'example cert\n',
8383
key: 'example key\n',
@@ -106,9 +106,9 @@ describe('toClientConfig', function () {
106106

107107
const clientConfig = toClientConfig(config)
108108

109-
clientConfig.host?.should.equal('boom')
110-
clientConfig.database?.should.equal('lala')
111-
clientConfig.ssl?.should.deep.equal({})
109+
expect(clientConfig.host).to.equal('boom')
110+
expect(clientConfig.database).to.equal('lala')
111+
expect(clientConfig.ssl).to.deep.equal({})
112112
})
113113
})
114114

packages/pg-connection-string/test/parse.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,4 +467,38 @@ describe('parse', function () {
467467
const subject = parse(connectionString)
468468
subject.port?.should.equal('1234')
469469
})
470+
471+
describe('prototype pollution protection', function () {
472+
it('returns object with null prototype', function () {
473+
const subject = parse('postgres://localhost/db')
474+
expect(Object.getPrototypeOf(subject)).to.equal(null)
475+
})
476+
477+
it('__proto__ query parameter is stored as regular property', function () {
478+
const subject = parse('postgres://localhost/db?__proto__=malicious')
479+
expect(Object.getPrototypeOf(subject)).to.equal(null)
480+
expect(subject['__proto__']).to.equal('malicious')
481+
// global Object.prototype should not be affected
482+
expect(({} as any).malicious).to.equal(undefined)
483+
})
484+
485+
it('constructor query parameter is stored as regular property', function () {
486+
const subject = parse('postgres://localhost/db?constructor=evil')
487+
expect(subject.constructor).to.equal('evil')
488+
})
489+
490+
it('prototype query parameter is stored as regular property', function () {
491+
const subject = parse('postgres://localhost/db?prototype=evil')
492+
expect(subject['prototype']).to.equal('evil')
493+
})
494+
495+
it('multiple dangerous query parameters are handled safely', function () {
496+
const subject = parse('postgres://localhost/db?__proto__=a&constructor=b&prototype=c&toString=d')
497+
expect(Object.getPrototypeOf(subject)).to.equal(null)
498+
expect(subject['__proto__']).to.equal('a')
499+
expect(subject.constructor).to.equal('b')
500+
expect(subject['prototype']).to.equal('c')
501+
expect(subject['toString']).to.equal('d')
502+
})
503+
})
470504
})

0 commit comments

Comments
 (0)