Skip to content

Commit

Permalink
JS-164 Improve S5122: Detect origin reflection
Browse files Browse the repository at this point in the history
  • Loading branch information
yassin-kammoun-sonarsource committed Jun 4, 2024
1 parent 70b20d7 commit b2b9ea6
Show file tree
Hide file tree
Showing 13 changed files with 526 additions and 379 deletions.

This file was deleted.

7 changes: 0 additions & 7 deletions its/ruling/src/test/expected/jsts/p5.js/javascript-S5122.json

This file was deleted.

This file was deleted.

10 changes: 0 additions & 10 deletions its/ruling/src/test/expected/jsts/yaml/javascript-S5122.json

This file was deleted.

7 changes: 6 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions packages/jsts/src/rules/S5122/cb.cors.fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const express = require('express');
const cors = require('cors');

const app1 = express();
app1.use(cors()); // Noncompliant

const app2 = express();
app2.use(cors({})); // Noncompliant

const app3 = express();
app3.use(cors({ origin: '*' })); // Noncompliant

const app4 = express();
const corsOptions = { origin: '*' };
// ^^^^^^^^^^^> {{Sensitive configuration}}
app4.use(cors(corsOptions)); // Noncompliant {{Make sure that enabling CORS is safe here.}}
//^^^^^^^^

const app5 = express();
const corsOpts = { origin: '*' };
const corsHandler = cors(corsOpts);
app5.use(corsHandler); // Noncompliant

const app42 = express();
app42.use();
app42.use(undefined);
app42.use('cors');
app42.use(foo());
app42.use(cors(42));
app42.use(cors({ origin: 'value' }));
52 changes: 52 additions & 0 deletions packages/jsts/src/rules/S5122/cb.http.fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const http = require('http');

function listener(req, res) {
res.writeHead(200, { 'Access-Control-Allow-Origin': '*' }); // Noncompliant
res.end('ok');
}

http.createServer(listener);

http.createServer((_, res) => {
res.writeHead(200, { 'Access-Control-Allow-Origin': '*' }); // Noncompliant
res.end('ok');
});

http.createServer((_, res) => {
const header = { 'Access-Control-Allow-Origin': '*' };
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^> {{Sensitive configuration}}
res.writeHead(200, header); // Noncompliant {{Make sure that enabling CORS is safe here.}}
//^^^^^^^^^^^^^
res.end('ok');
});

http.createServer((_, res) => {
const access = '*';
const header = { 'Access-Control-Allow-Origin': access };
res.writeHead(200, header); // Noncompliant
res.end('ok');
});

http.createServer();
http.createServer(undefined);
http.createServer('listener');
http.createServer(_ => {});
http.createServer((req, res) => {});
http.createServer((_, res) => {
res.end('ok');
});
http.createServer((_, res) => {
res.writeHead(200, 'header');
});
http.createServer((_, res) => {
res.writeHead(200, {});
});
http.createServer((_, res) => {
res.writeHead(200, { undefined });
});
http.createServer((_, res) => {
res.writeHead(200, { header: 'value' });
});
http.createServer((_, res) => {
res.writeHead(200, { 'Access-Control-Allow-Origin': 'value' });
});
23 changes: 23 additions & 0 deletions packages/jsts/src/rules/S5122/cb.reproducer.fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Code reproducer from R&D
var express = require('express');
var app = express();

function cgiHandler(req, res) {
if (UP_PATH_REGEXP.test(req.path)) {
return res.status(403).end('Forbidden');
}
if (req.headers.origin) {
res.setHeader('access-control-allow-origin', req.headers.origin); // Noncompliant
res.setHeader('access-control-allow-credentials', true);
}
// ...
}

app.all('/cgi-bin/sessions/*', cgiHandler);

app.all('/cgi-bin/*', function(req, res, next) {
req.isUploadReq = UPLOAD_URLS.indexOf(req.path) !== -1;
return req.isUploadReq ? uploadUrlencodedParser(req, res, next) : urlencodedParser(req, res, next);
}, function(req, res, next) {
return req.isUploadReq ? uploadJsonParser(req, res, next) : jsonParser(req, res, next);
}, cgiHandler);
79 changes: 79 additions & 0 deletions packages/jsts/src/rules/S5122/cb.tainted.fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const express = require('express');
const app = express();

app.all('*', (req, res) => {
res.setHeader('access-control-allow-origin', req.headers.origin); // Noncompliant
});

app.all('*', (req, res) => {
res.setHeader('access-control-allow-origin', req.header('origin')); // Noncompliant
});

app.all('*', (req, res) => {
const origin = req.headers.origin;
// ^^^^^^^^^^^^^^^^^^> {{Sensitive configuration}}
res.setHeader('access-control-allow-origin', origin); // Noncompliant {{Make sure that enabling CORS is safe here.}}
//^^^^^^^^^^^^^
});

app.all('*', (req, res) => {
const origin = req.header('origin');
res.setHeader('access-control-allow-origin', origin); // Noncompliant
});

app.all('*', (req, res) => {
res.setHeader('access-control-allow-origin', sanitize(req.headers.origin));
});

app.all('*', (req, res) => {
res.setHeader('access-control-allow-origin', sanitize(req.header('origin')));
});

app.all('*', (req, res) => {
const origin = req.headers.origin;
const sanitized = sanitize(origin);
res.setHeader('access-control-allow-origin', sanitized);
});

app.all('*', (req, res) => {
const origin = req.header('Origin');
const sanitized = sanitize(origin);
res.setHeader('access-control-allow-origin', sanitized);
});

app.all('*', (req, res) => {
const origin = req.headers.origin;
if (origin === 'https://www.trusted.com') {
res.setHeader('access-control-allow-origin', origin);
}
});

app.all('*', (req, res) => {
const origin = req.header('origin');
if (origin === 'https://www.trusted.com') {
res.setHeader('access-control-allow-origin', origin);
}
});

app.all('*');
app.all('*', 42);
app.all('*', undefined);
app.all('*', ({}));
app.all('*', () => {});
app.all('*', req => {});
app.all('*', ({}) => {});
app.all('*', (req, res) => {});
app.all('*', (req, {}) => {});
app.all('*', (req, res) => { res; });
app.all('*', (req, res) => { res.end('ok'); });
app.all('*', (req, res) => { res.setHeader(); });
app.all('*', (req, res) => { res.setHeader(42); });
app.all('*', (req, res) => { res.setHeader('foo'); });
app.all('*', (req, res) => { res.setHeader('access-control-allow-origin'); });
app.all('*', (req, res) => { res.setHeader('access-control-allow-origin', undefined); });
app.all('*', (req, res) => { res.setHeader('access-control-allow-origin', foo()); });
app.all('*', (req, res) => { res.setHeader('access-control-allow-origin', req.header()); });
app.all('*', (req, res) => { res.setHeader('access-control-allow-origin', req.header(42)); });
app.all('*', (req, res) => { res.setHeader('access-control-allow-origin', req.header('foo')); });
app.all('*', (req, res) => { res.setHeader('access-control-allow-origin', req.headers); });
app.all('*', (req, res) => { res.setHeader('access-control-allow-origin', req.headers.foo); });
28 changes: 28 additions & 0 deletions packages/jsts/src/rules/S5122/cb.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { check } from '../tools';
import { rule } from './';
import path from 'path';

const sonarId = path.basename(__dirname);

describe('Rule S5122', () => {
check(sonarId, rule, __dirname);
});
Loading

0 comments on commit b2b9ea6

Please sign in to comment.