diff --git a/api/routes/erase.js b/api/routes/erase.js index 02d46cc..afbf95c 100644 --- a/api/routes/erase.js +++ b/api/routes/erase.js @@ -5,6 +5,15 @@ const { sendErasureMail, PROVIDER_DATA } = require('../services/mailer'); const ALLOWED_PROVIDERS = new Set(Object.keys(PROVIDER_DATA)); +/* Elimina CRLF y chars de control — previene header injection en el cuerpo del email */ +function sanitizeField(raw, maxLen) { + return String(raw || '') + .replace(/[\r\n\t\x00-\x1F\x7F]/g, ' ') // CRLF → espacio, no rompe el texto + .replace(/\s{2,}/g, ' ') // colapsa espacios múltiples + .trim() + .slice(0, maxLen); +} + module.exports = async (req, res) => { try { const { provider, email, @@ -26,11 +35,11 @@ module.exports = async (req, res) => { return res.status(400).json({ error: 'Email inválido' }); } - // Límites de longitud en campos opcionales (defensa en profundidad) - const nickname = String(rawNick || '').slice(0, 100).trim(); - const phone = String(rawPhone || '').slice(0, 30).trim(); - const address = String(rawAddr || '').slice(0, 300).trim(); - const extra = String(rawExtra || '').slice(0, 500).trim(); + // Sanitizar campos opcionales: longitud + strip CRLF (header injection) + const nickname = sanitizeField(rawNick, 100); + const phone = sanitizeField(rawPhone, 30); + const address = sanitizeField(rawAddr, 300); + const extra = sanitizeField(rawExtra, 500); // Hash irreversible para referencia (auditoría sin almacenar PII) const hash = crypto diff --git a/public/egosurfing.html b/public/egosurfing.html index 1c395b0..c558f17 100644 --- a/public/egosurfing.html +++ b/public/egosurfing.html @@ -809,7 +809,7 @@ function renderResults(results) { Ver página - ${rtbfUrl ? ` + ${rtbfUrl ? ` Solicitar eliminación ` : ''}