From f354755871c5727a442be6d66ae1d5d282a15a60 Mon Sep 17 00:00:00 2001 From: pm Date: Mon, 15 Jun 2026 22:30:23 +0100 Subject: [PATCH 01/18] Gitleaks Validation --- backend/server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/server.js b/backend/server.js index 51387fd..baa3de4 100644 --- a/backend/server.js +++ b/backend/server.js @@ -8,6 +8,7 @@ const app = express(); app.disable('x-powered-by'); const PORT = process.env.PORT || 3000; +const api_key = 'some_key_here' app.use(cors()); app.use(express.json()); -- 2.52.0 From 1b301f879c73164b1a20d24292a4145be7c7db7d Mon Sep 17 00:00:00 2001 From: pm Date: Mon, 15 Jun 2026 23:31:02 +0100 Subject: [PATCH 02/18] Gitleaks Validation v2 --- backend/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/server.js b/backend/server.js index baa3de4..dc2e824 100644 --- a/backend/server.js +++ b/backend/server.js @@ -8,7 +8,7 @@ const app = express(); app.disable('x-powered-by'); const PORT = process.env.PORT || 3000; -const api_key = 'some_key_here' +const api_key = 'xK9#vL!2pQz8$mN@5yT' app.use(cors()); app.use(express.json()); -- 2.52.0 From 021e844a4a7a5e8f8ab9a0db833944bb741ba8f1 Mon Sep 17 00:00:00 2001 From: pm Date: Mon, 15 Jun 2026 23:33:53 +0100 Subject: [PATCH 03/18] Gitleaks Validation v2 --- backend/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/server.js b/backend/server.js index dc2e824..a5c764b 100644 --- a/backend/server.js +++ b/backend/server.js @@ -8,7 +8,7 @@ const app = express(); app.disable('x-powered-by'); const PORT = process.env.PORT || 3000; -const api_key = 'xK9#vL!2pQz8$mN@5yT' +const api_key = 'ghp_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r' app.use(cors()); app.use(express.json()); -- 2.52.0 From fb337cfe01a4fe35abe14c4960bb767dbe0f6351 Mon Sep 17 00:00:00 2001 From: pm Date: Mon, 15 Jun 2026 23:50:35 +0100 Subject: [PATCH 04/18] Unit Tests Validation --- backend/server.js | 1 - tests/core.test.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/server.js b/backend/server.js index a5c764b..51387fd 100644 --- a/backend/server.js +++ b/backend/server.js @@ -8,7 +8,6 @@ const app = express(); app.disable('x-powered-by'); const PORT = process.env.PORT || 3000; -const api_key = 'ghp_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r' app.use(cors()); app.use(express.json()); diff --git a/tests/core.test.js b/tests/core.test.js index 31446fb..28228b9 100644 --- a/tests/core.test.js +++ b/tests/core.test.js @@ -27,7 +27,7 @@ describe('Enterprise Application Flow & API Validation', () => { describe('1. Static Web Routing', () => { it('Should return 200 OK and text/html for the Home Page (/)', async () => { const response = await request(app).get('/'); - expect(response.status).toBe(200); + expect(response.status).toBe(500); expect(response.headers['content-type']).toMatch(/text\/html/); }); -- 2.52.0 From 4fc7cb055f57a15a20506c1d1dd3d8e3fe59ee12 Mon Sep 17 00:00:00 2001 From: pm Date: Tue, 16 Jun 2026 00:00:12 +0100 Subject: [PATCH 05/18] Trivy Validation --- package-lock.json | 7 ------- tests/core.test.js | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0c659ad..c8bf9fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "dependencies": { "cors": "^2.8.5", "express": "^4.18.2", - "lodash": "4.17.15", "nodemailer": "^8.0.11" }, "devDependencies": { @@ -3900,12 +3899,6 @@ "node": ">=8" } }, - "node_modules/lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "license": "MIT" - }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", diff --git a/tests/core.test.js b/tests/core.test.js index 28228b9..31446fb 100644 --- a/tests/core.test.js +++ b/tests/core.test.js @@ -27,7 +27,7 @@ describe('Enterprise Application Flow & API Validation', () => { describe('1. Static Web Routing', () => { it('Should return 200 OK and text/html for the Home Page (/)', async () => { const response = await request(app).get('/'); - expect(response.status).toBe(500); + expect(response.status).toBe(200); expect(response.headers['content-type']).toMatch(/text\/html/); }); -- 2.52.0 From c7e505765a127d5c5920a9b16bf77f933993e128 Mon Sep 17 00:00:00 2001 From: pm Date: Tue, 16 Jun 2026 00:01:55 +0100 Subject: [PATCH 06/18] Trivy Validation v2 [fixed] --- package-lock.json | 8 ++++++++ package.json | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index c8bf9fe..d4e79c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ }, "devDependencies": { "jest": "^30.4.2", + "lodash": "4.17.15", "supertest": "^7.2.2" } }, @@ -3899,6 +3900,13 @@ "node": ">=8" } }, + "node_modules/lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true, + "license": "MIT" + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", diff --git a/package.json b/package.json index 949fef2..eed0cb9 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ }, "devDependencies": { "jest": "^30.4.2", - "supertest": "^7.2.2" + "supertest": "^7.2.2", + "lodash": "4.17.15" } } \ No newline at end of file -- 2.52.0 From 6fc77e5569c0a74ed171746b7d72265d29445fb5 Mon Sep 17 00:00:00 2001 From: pm Date: Tue, 16 Jun 2026 00:04:56 +0100 Subject: [PATCH 07/18] Trivy Validation v3 [fixed] --- package-lock.json | 3 +-- package.json | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index d4e79c5..0c659ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,11 +11,11 @@ "dependencies": { "cors": "^2.8.5", "express": "^4.18.2", + "lodash": "4.17.15", "nodemailer": "^8.0.11" }, "devDependencies": { "jest": "^30.4.2", - "lodash": "4.17.15", "supertest": "^7.2.2" } }, @@ -3904,7 +3904,6 @@ "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true, "license": "MIT" }, "node_modules/lru-cache": { diff --git a/package.json b/package.json index eed0cb9..f98ae6d 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,11 @@ "dependencies": { "cors": "^2.8.5", "express": "^4.18.2", - "nodemailer": "^8.0.11" + "nodemailer": "^8.0.11", + "lodash": "4.17.15" }, "devDependencies": { "jest": "^30.4.2", - "supertest": "^7.2.2", - "lodash": "4.17.15" + "supertest": "^7.2.2" } } \ No newline at end of file -- 2.52.0 From fd94417c8d5a70a2dee9806837b6f2cb4df2671c Mon Sep 17 00:00:00 2001 From: pm Date: Tue, 16 Jun 2026 00:40:19 +0100 Subject: [PATCH 08/18] SonarQube Validation --- backend/server.js | 6 +++--- package-lock.json | 12 +----------- package.json | 1 - 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/backend/server.js b/backend/server.js index 51387fd..499cc37 100644 --- a/backend/server.js +++ b/backend/server.js @@ -23,9 +23,9 @@ app.get('/careers', (req, res) => res.sendFile(path.join(__dirname, '../frontend app.get('/contact', (req, res) => res.sendFile(path.join(__dirname, '../frontend/contact.html'))); // ========================================== -// VULNERÁVEL (OWASP ZAP) +// VULNERÁVEL (OWASP ZAP) / SonarQube // ========================================== -/*app.get('/api/search', (req, res) => { +app.get('/api/search', (req, res) => { const termo = req.query.q || ''; // A vulnerabilidade crítica: devolver o input diretamente no HTML res.send(` @@ -37,7 +37,7 @@ app.get('/contact', (req, res) => res.sendFile(path.join(__dirname, '../frontend `); -});*/ +}); // Configuração do transporte de E-mail (Mocks de teste vs Produção) let transporter; diff --git a/package-lock.json b/package-lock.json index 0c659ad..fc94e4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,7 @@ "dependencies": { "cors": "^2.8.5", "express": "^4.18.2", - "lodash": "4.17.15", - "nodemailer": "^8.0.11" + "lodash": "4.17.15" }, "devDependencies": { "jest": "^30.4.2", @@ -4123,15 +4122,6 @@ "node": ">=18" } }, - "node_modules/nodemailer": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.11.tgz", - "integrity": "sha512-nrO/pDAUKl+wXX+lx16tDLbnm0fW6sK/x8mgohaCpg+CdCEl482bD4tCuAZk2DyliruiNTIZxRCoWkDqJEnAiA==", - "license": "MIT-0", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", diff --git a/package.json b/package.json index f98ae6d..7b3ac35 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "dependencies": { "cors": "^2.8.5", "express": "^4.18.2", - "nodemailer": "^8.0.11", "lodash": "4.17.15" }, "devDependencies": { -- 2.52.0 From e9e243ee42ea9ed97af920940a29f01a9ef438c7 Mon Sep 17 00:00:00 2001 From: pm Date: Tue, 16 Jun 2026 00:42:29 +0100 Subject: [PATCH 09/18] SonarQube Validation v2 --- tests/core.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core.test.js b/tests/core.test.js index 31446fb..bc38cee 100644 --- a/tests/core.test.js +++ b/tests/core.test.js @@ -36,7 +36,7 @@ describe('Enterprise Application Flow & API Validation', () => { expect(response.status).toBe(404); }); - /*// OWASP ZAP (/api/search) + // OWASP ZAP (/api/search) it('Should reflect the search query in the HTML response (/api/search) - Vulnerable to XSS', async () => { const maliciousPayload = ''; const response = await request(app).get(`/api/search?q=${maliciousPayload}`); @@ -44,7 +44,7 @@ describe('Enterprise Application Flow & API Validation', () => { expect(response.status).toBe(200); // Verifica se o payload é refletido exatamente como entrou (confirmando a vulnerabilidade) expect(response.text).toContain(`Resultados para: ${maliciousPayload}`); - });*/ + }); }); // ========================================== -- 2.52.0 From 2ddbf37ca2c2db783ffefdf1630796d36f71f023 Mon Sep 17 00:00:00 2001 From: pm Date: Tue, 16 Jun 2026 00:45:39 +0100 Subject: [PATCH 10/18] SonarQube Validation v3 --- package-lock.json | 17 ++++++++++------- package.json | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index fc94e4c..c8bf9fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "cors": "^2.8.5", "express": "^4.18.2", - "lodash": "4.17.15" + "nodemailer": "^8.0.11" }, "devDependencies": { "jest": "^30.4.2", @@ -3899,12 +3899,6 @@ "node": ">=8" } }, - "node_modules/lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "license": "MIT" - }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4122,6 +4116,15 @@ "node": ">=18" } }, + "node_modules/nodemailer": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.11.tgz", + "integrity": "sha512-nrO/pDAUKl+wXX+lx16tDLbnm0fW6sK/x8mgohaCpg+CdCEl482bD4tCuAZk2DyliruiNTIZxRCoWkDqJEnAiA==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", diff --git a/package.json b/package.json index 7b3ac35..949fef2 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "dependencies": { "cors": "^2.8.5", "express": "^4.18.2", - "lodash": "4.17.15" + "nodemailer": "^8.0.11" }, "devDependencies": { "jest": "^30.4.2", -- 2.52.0 From 414ebd29ad53f279aa27eb4732f66420a3a3f915 Mon Sep 17 00:00:00 2001 From: pm Date: Tue, 16 Jun 2026 01:12:10 +0100 Subject: [PATCH 11/18] SonarQube Validation v4 --- backend/server.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/backend/server.js b/backend/server.js index 499cc37..d8e6c92 100644 --- a/backend/server.js +++ b/backend/server.js @@ -23,9 +23,9 @@ app.get('/careers', (req, res) => res.sendFile(path.join(__dirname, '../frontend app.get('/contact', (req, res) => res.sendFile(path.join(__dirname, '../frontend/contact.html'))); // ========================================== -// VULNERÁVEL (OWASP ZAP) / SonarQube +// VULNERÁVEL (OWASP ZAP) // ========================================== -app.get('/api/search', (req, res) => { +/*app.get('/api/search', (req, res) => { const termo = req.query.q || ''; // A vulnerabilidade crítica: devolver o input diretamente no HTML res.send(` @@ -37,6 +37,15 @@ app.get('/api/search', (req, res) => { `); +});*/ + +app.get('/api/calculate', (req, res) => { + const mathExpression = req.query.expr || '2+2'; + + // VULNERABILIDADE CRÍTICA: O eval() executa qualquer código cego que o utilizador envie + const result = eval(mathExpression); + + res.json({ result: result }); }); // Configuração do transporte de E-mail (Mocks de teste vs Produção) -- 2.52.0 From 5929b935c1ae12a493e34563a8b8cd03d6b2deee Mon Sep 17 00:00:00 2001 From: pm Date: Tue, 16 Jun 2026 01:14:24 +0100 Subject: [PATCH 12/18] SonarQube Validation v5 --- tests/core.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core.test.js b/tests/core.test.js index bc38cee..2f2f3e6 100644 --- a/tests/core.test.js +++ b/tests/core.test.js @@ -37,7 +37,7 @@ describe('Enterprise Application Flow & API Validation', () => { }); // OWASP ZAP (/api/search) - it('Should reflect the search query in the HTML response (/api/search) - Vulnerable to XSS', async () => { + /* it('Should reflect the search query in the HTML response (/api/search) - Vulnerable to XSS', async () => { const maliciousPayload = ''; const response = await request(app).get(`/api/search?q=${maliciousPayload}`); @@ -45,7 +45,7 @@ describe('Enterprise Application Flow & API Validation', () => { // Verifica se o payload é refletido exatamente como entrou (confirmando a vulnerabilidade) expect(response.text).toContain(`Resultados para: ${maliciousPayload}`); }); - }); + });*/ // ========================================== // 2. API BUSINESS LOGIC & VALIDATION TESTS -- 2.52.0 From 0d221313e902e1183a38d544e7c75d07097ab451 Mon Sep 17 00:00:00 2001 From: pm Date: Tue, 16 Jun 2026 01:17:02 +0100 Subject: [PATCH 13/18] SonarQube Validation v6 --- tests/core.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core.test.js b/tests/core.test.js index 2f2f3e6..f55a0bc 100644 --- a/tests/core.test.js +++ b/tests/core.test.js @@ -44,8 +44,8 @@ describe('Enterprise Application Flow & API Validation', () => { expect(response.status).toBe(200); // Verifica se o payload é refletido exatamente como entrou (confirmando a vulnerabilidade) expect(response.text).toContain(`Resultados para: ${maliciousPayload}`); - }); - });*/ + });*/ + }); // ========================================== // 2. API BUSINESS LOGIC & VALIDATION TESTS -- 2.52.0 From a6a7f3b0b5d73db7b08e529e9e5a8751c68b5d7e Mon Sep 17 00:00:00 2001 From: pm Date: Tue, 16 Jun 2026 01:24:40 +0100 Subject: [PATCH 14/18] All Good Validation --- backend/server.js | 24 ------------------------ tests/core.test.js | 9 --------- 2 files changed, 33 deletions(-) diff --git a/backend/server.js b/backend/server.js index d8e6c92..322a9d7 100644 --- a/backend/server.js +++ b/backend/server.js @@ -22,31 +22,7 @@ app.get('/about', (req, res) => res.sendFile(path.join(__dirname, '../frontend/a app.get('/careers', (req, res) => res.sendFile(path.join(__dirname, '../frontend/careers.html'))); app.get('/contact', (req, res) => res.sendFile(path.join(__dirname, '../frontend/contact.html'))); -// ========================================== -// VULNERÁVEL (OWASP ZAP) -// ========================================== -/*app.get('/api/search', (req, res) => { - const termo = req.query.q || ''; - // A vulnerabilidade crítica: devolver o input diretamente no HTML - res.send(` - - Resultados - -

Resultados para: ${termo}

- Voltar - - - `); -});*/ -app.get('/api/calculate', (req, res) => { - const mathExpression = req.query.expr || '2+2'; - - // VULNERABILIDADE CRÍTICA: O eval() executa qualquer código cego que o utilizador envie - const result = eval(mathExpression); - - res.json({ result: result }); -}); // Configuração do transporte de E-mail (Mocks de teste vs Produção) let transporter; diff --git a/tests/core.test.js b/tests/core.test.js index f55a0bc..359428e 100644 --- a/tests/core.test.js +++ b/tests/core.test.js @@ -36,15 +36,6 @@ describe('Enterprise Application Flow & API Validation', () => { expect(response.status).toBe(404); }); - // OWASP ZAP (/api/search) - /* it('Should reflect the search query in the HTML response (/api/search) - Vulnerable to XSS', async () => { - const maliciousPayload = ''; - const response = await request(app).get(`/api/search?q=${maliciousPayload}`); - - expect(response.status).toBe(200); - // Verifica se o payload é refletido exatamente como entrou (confirmando a vulnerabilidade) - expect(response.text).toContain(`Resultados para: ${maliciousPayload}`); - });*/ }); // ========================================== -- 2.52.0 From 35260c3717b62e99f74e1b3999329b8657dd9315 Mon Sep 17 00:00:00 2001 From: pm Date: Tue, 16 Jun 2026 01:34:41 +0100 Subject: [PATCH 15/18] SonarQube Validation --- backend/server.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backend/server.js b/backend/server.js index 322a9d7..44614dd 100644 --- a/backend/server.js +++ b/backend/server.js @@ -22,6 +22,15 @@ app.get('/about', (req, res) => res.sendFile(path.join(__dirname, '../frontend/a app.get('/careers', (req, res) => res.sendFile(path.join(__dirname, '../frontend/careers.html'))); app.get('/contact', (req, res) => res.sendFile(path.join(__dirname, '../frontend/contact.html'))); +app.get('/api/calculate', (req, res) => { + const mathExpression = req.query.expr || '2+2'; + + // VULNERABILIDADE CRÍTICA: O eval() executa + // qualquer código cego que o utilizador envie + const result = eval(mathExpression); + + res.json({ result: result }); +}); // Configuração do transporte de E-mail (Mocks de teste vs Produção) -- 2.52.0 From c63239e7ee68b23eaee0eb4119878b1e4733f229 Mon Sep 17 00:00:00 2001 From: pedro Date: Tue, 16 Jun 2026 16:02:41 +0100 Subject: [PATCH 16/18] OWASP ZAP Validation --- backend/server.js | 70 +++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 39 deletions(-) diff --git a/backend/server.js b/backend/server.js index 44614dd..0210e66 100644 --- a/backend/server.js +++ b/backend/server.js @@ -13,26 +13,39 @@ app.use(cors()); app.use(express.json()); app.use(express.urlencoded({ extended: true })); +// ========================================== +// ROTA LIMPA (Passa no SonarQube, chumba no ZAP) +// ========================================== + +// Modificamos a rota principal temporariamente para o ZAP encontrar o link +app.get('/', (req, res) => { + res.send(` + + +

Bem-vindo a Apex Solutions

+ + Pesquisar + + + `); +}); + +// A rota vulnerável a XSS que o SonarQube ignora (por ser versão gratuita) +app.get('/api/search', (req, res) => { + const termo = req.query.q || ''; + // Vulnerabilidade Crítica: XSS Refletido + res.send(`

Resultados para: ${termo}

`); +}); + // Serve a pasta frontend app.use(express.static(path.join(__dirname, '../frontend'), { extensions: ['html'] })); -// Rotas das 4 páginas estáticas -app.get('/', (req, res) => res.sendFile(path.join(__dirname, '../frontend/index.html'))); +// Rotas das páginas estáticas +// app.get('/', (req, res) => res.sendFile(path.join(__dirname, '../frontend/index.html'))); // <-- COMENTADO PARA NÃO DAR CONFLITO app.get('/about', (req, res) => res.sendFile(path.join(__dirname, '../frontend/about.html'))); app.get('/careers', (req, res) => res.sendFile(path.join(__dirname, '../frontend/careers.html'))); app.get('/contact', (req, res) => res.sendFile(path.join(__dirname, '../frontend/contact.html'))); -app.get('/api/calculate', (req, res) => { - const mathExpression = req.query.expr || '2+2'; - - // VULNERABILIDADE CRÍTICA: O eval() executa - // qualquer código cego que o utilizador envie - const result = eval(mathExpression); - - res.json({ result: result }); -}); - - // Configuração do transporte de E-mail (Mocks de teste vs Produção) let transporter; @@ -51,11 +64,10 @@ if (process.env.NODE_ENV === 'test') { }); } -// Endpoint do Formulário de Contacto (Com a armadilha validada pelo Jest) +// Endpoint do Formulário de Contacto app.post('/api/contact', async (req, res) => { const { firstName, lastName, email, company, message } = req.body; - // Se faltarem dados, devolvemos HTML para simular XSS e bater com o teste unitário if (!email || !message) { res.setHeader('Content-Type', 'text/html'); return res.status(400).send(` @@ -70,35 +82,15 @@ app.post('/api/contact', async (req, res) => { from: '"Apex Solutions" ', to: email, subject: `Confirmation: We received your request, ${firstName}!`, - html: ` -
-

Hello ${firstName} ${lastName},

-

- Thank you for reaching out to Apex Solutions. This is an automated confirmation. -

-
-

Summary of your submission:

-

Subject/Company: ${company || 'Not specified'}

-

"${message}"

-
-

- Our team will get back to you within 24 business hours. -

-
-

- Best regards,
Apex Solutions Corporate Team -

-
- ` + html: `

Thank you for reaching out to Apex Solutions.

` // Encurtado aqui apenas para não poluir o ecrã, podes manter o teu HTML original! }; const info = await transporter.sendMail(mailOptions); - console.log(`[Email Sent Automatically to ${email}] Message ID: ${info.messageId}`); - - res.status(200).json({ success: true, message: 'Thank you! A confirmation email has been dispatched.' }); + console.log(`[Email Sent] Message ID: ${info.messageId}`); + res.status(200).json({ success: true, message: 'Thank you! Email dispatched.' }); } catch (error) { console.error(`[Email Error]:`, error); - res.status(500).json({ error: 'Internal server error. Could not send confirmation email.' }); + res.status(500).json({ error: 'Internal server error.' }); } }); -- 2.52.0 From a213cc94825869ca9bd9add5dae15ebe5990bb11 Mon Sep 17 00:00:00 2001 From: pedro Date: Tue, 16 Jun 2026 16:09:04 +0100 Subject: [PATCH 17/18] OWASP ZAP Validation v2 --- backend/server.js | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/backend/server.js b/backend/server.js index 0210e66..7a53688 100644 --- a/backend/server.js +++ b/backend/server.js @@ -13,24 +13,24 @@ app.use(cors()); app.use(express.json()); app.use(express.urlencoded({ extended: true })); + // ========================================== // ROTA LIMPA (Passa no SonarQube, chumba no ZAP) // ========================================== -// Modificamos a rota principal temporariamente para o ZAP encontrar o link +// Modificamos a rota principal temporariamente para o ZAP encontrar o link e atacar app.get('/', (req, res) => { res.send(`

Bem-vindo a Apex Solutions

- Pesquisar `); }); -// A rota vulnerável a XSS que o SonarQube ignora (por ser versão gratuita) +// A rota vulnerável a XSS que o SonarQube (versão gratuita) ignora, mas o ZAP destrói app.get('/api/search', (req, res) => { const termo = req.query.q || ''; // Vulnerabilidade Crítica: XSS Refletido @@ -40,12 +40,14 @@ app.get('/api/search', (req, res) => { // Serve a pasta frontend app.use(express.static(path.join(__dirname, '../frontend'), { extensions: ['html'] })); -// Rotas das páginas estáticas -// app.get('/', (req, res) => res.sendFile(path.join(__dirname, '../frontend/index.html'))); // <-- COMENTADO PARA NÃO DAR CONFLITO +// Rotas das páginas estáticas (A rota '/' original foi comentada para não dar conflito com a do ZAP) +// app.get('/', (req, res) => res.sendFile(path.join(__dirname, '../frontend/index.html'))); app.get('/about', (req, res) => res.sendFile(path.join(__dirname, '../frontend/about.html'))); app.get('/careers', (req, res) => res.sendFile(path.join(__dirname, '../frontend/careers.html'))); app.get('/contact', (req, res) => res.sendFile(path.join(__dirname, '../frontend/contact.html'))); +// O eval() FOI REMOVIDO DAQUI PARA O SONARQUBE NÃO BLOQUEAR! + // Configuração do transporte de E-mail (Mocks de teste vs Produção) let transporter; @@ -64,10 +66,11 @@ if (process.env.NODE_ENV === 'test') { }); } -// Endpoint do Formulário de Contacto +// Endpoint do Formulário de Contacto (Com a armadilha validada pelo Jest) app.post('/api/contact', async (req, res) => { const { firstName, lastName, email, company, message } = req.body; + // Se faltarem dados, devolvemos HTML para simular XSS e bater com o teste unitário if (!email || !message) { res.setHeader('Content-Type', 'text/html'); return res.status(400).send(` @@ -82,15 +85,35 @@ app.post('/api/contact', async (req, res) => { from: '"Apex Solutions" ', to: email, subject: `Confirmation: We received your request, ${firstName}!`, - html: `

Thank you for reaching out to Apex Solutions.

` // Encurtado aqui apenas para não poluir o ecrã, podes manter o teu HTML original! + html: ` +
+

Hello ${firstName} ${lastName},

+

+ Thank you for reaching out to Apex Solutions. This is an automated confirmation. +

+
+

Summary of your submission:

+

Subject/Company: ${company || 'Not specified'}

+

"${message}"

+
+

+ Our team will get back to you within 24 business hours. +

+
+

+ Best regards,
Apex Solutions Corporate Team +

+
+ ` }; const info = await transporter.sendMail(mailOptions); - console.log(`[Email Sent] Message ID: ${info.messageId}`); - res.status(200).json({ success: true, message: 'Thank you! Email dispatched.' }); + console.log(`[Email Sent Automatically to ${email}] Message ID: ${info.messageId}`); + + res.status(200).json({ success: true, message: 'Thank you! A confirmation email has been dispatched.' }); } catch (error) { console.error(`[Email Error]:`, error); - res.status(500).json({ error: 'Internal server error.' }); + res.status(500).json({ error: 'Internal server error. Could not send confirmation email.' }); } }); -- 2.52.0 From f386e25432e795d7209753cf17eb1cf2f60d0850 Mon Sep 17 00:00:00 2001 From: pedro Date: Tue, 16 Jun 2026 16:28:46 +0100 Subject: [PATCH 18/18] All Good --- backend/server.js | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/backend/server.js b/backend/server.js index 7a53688..7d19dbd 100644 --- a/backend/server.js +++ b/backend/server.js @@ -14,23 +14,6 @@ app.use(express.json()); app.use(express.urlencoded({ extended: true })); -// ========================================== -// ROTA LIMPA (Passa no SonarQube, chumba no ZAP) -// ========================================== - -// Modificamos a rota principal temporariamente para o ZAP encontrar o link e atacar -app.get('/', (req, res) => { - res.send(` - - -

Bem-vindo a Apex Solutions

- Pesquisar - - - `); -}); - -// A rota vulnerável a XSS que o SonarQube (versão gratuita) ignora, mas o ZAP destrói app.get('/api/search', (req, res) => { const termo = req.query.q || ''; // Vulnerabilidade Crítica: XSS Refletido -- 2.52.0