Incidente: Auditoría Suprema network SA5 — Broken Access Control, XSS, inyección cerrados
Resumen
Quinta y última auditoría del dominio network (SA5: Port connections / Cable report). Se confirmaron 18 hallazgos (3 ALTA, 6 MEDIA, 9 BAJA) en los endpoints y servicios de gestión de conexiones de puertos y generación de informes de cableado.
Hallazgos críticos cerrados:
- Broken Access Control sistémico: NINGÚN endpoint usaba
require_perm→ un usuarioreadonlypodía crear/borrar cableado y descargar el mapa de topología completo. Ahora 11 endpoints gateados. - XSS almacenado en Cable Report HTML: nombres de rack interpolados crudos en diagrama Mermaid con
securityLevel:'loose'. Sanado:securityLevel:'strict'+ escapado de labels. - Inyección de header y markdown:
Content-Dispositionmalformable desdescope_name; pipes en tablas podían romper/inyectar filas. Sanado con whitelist y escapado. - Duplicación de código (Regla 2): funciones
_port_labely_get_portsreplicadas en API y service. Extraída a nuevo móduloport_labels.py.
Hallazgos confirmados (18 total)
ALTA (3)
| Título | Dimensión | Archivo | Línea | Propuesta | Effort |
|---|---|---|---|---|---|
| Broken Access Control en mutaciones port_connections | Security | network/api/port_connections.py | 324, 468, 540 | Requerir require_perm(network, edit) en create_connection, create_device_connection, delete_connection | M |
| Broken Access Control en lecturas de topología y cable report | Security | network/api/port_connections.py, network/api/cable_report.py | múltiples | Requerir require_perm(network, view) en 6 endpoints de lectura/report | M |
| XSS almacenado en Cable Report HTML | Security | network/services/cable_report.py | 396, 418, 425, 459 | securityLevel:'strict' en Mermaid + sanitizar nombres de rack/location en labels + escapar bloque mermaid en _md_to_html | M |
MEDIA (6)
| Título | Dimensión | Archivo | Línea | Propuesta | Effort |
|---|---|---|---|---|---|
| Header Injection en Content-Disposition | Security | network/api/cable_report.py | 37 | Whitelist de chars en scope_name para filename | S |
| Markdown Injection en tablas del report | Security | network/services/cable_report.py | formato celdas | Escapar | y \n en valores de tabla | S |
| ReDoS en regex de parseo SNMP/SSH | Performance | network/services/port_suggestion.py, ssh_reader.py | múltiples | Revisar backtracking en PORT_PATTERNS y regex de parseo Cisco/Juniper | M |
| SSRF en PortConfigReader (defensa en profundidad) | Security | network/services/port_config_reader/reader.py | 30 | Validar is_private_ip dentro del reader, no confiar ciegamente en caller | M |
| 200-con-fallo en read_auto | Correctness | network/services/port_config_reader/reader.py | 63, 95 | Distinguir exito real vs. “error al leer” en respuesta (Regla 15) | S |
| datetime.now() naive en cable_report | Correctness | network/services/cable_report.py | 238 | Usar timezone.localtime() (Regla 25) | S |
BAJA (9)
- Duplicación de
_port_label/_get_ports(Regla 2) → Extraída aport_labels.py✅ - Mermaid CDN externo (supply-chain/offline)
- Sin rate-limit en endpoints del report (DoS amplificación)
- Sin cap de tamaño en
collect_cable_data→ Cap defensivoMAX_CONNECTIONS=20000✅ - ReDoS en
_extract_port_key(dato de vecino LLDP/CDP) → Acotado a 128 chars ✅ _escincompleto (falta') → Migrado ahtml.escape(..., quote=True)✅- Falta test de autorización para estos endpoints
- Falta test de XSS en el Cable Report
- Dead code / imports inline en servicios
Rectificaciones implementadas
Security (merged en commit 14e9074):
- ✅
require_perm(network, "edit")encreate_connection,create_device_connection,delete_connection - ✅
require_perm(network, "view")en 6 endpoints de lectura y 3 endpoints del Cable Report (JSON/Markdown/HTML) - ✅
securityLevel:'strict'en Mermaid + función_mermaid_textque elimina<>[]{}|"y acota longitud - ✅ Whitelist regex en
filenamedelContent-Disposition(solo[A-Za-z0-9._-]) - ✅ Escape de
|y\nen celdas de tabla Markdown (_cell) - ✅
timezone.localtime()paragenerated_at(Regla 25) - ✅ Cap defensivo
MAX_CONNECTIONS=20000con truncado logged - ✅ Acotado
_extract_port_keya 128 chars (anti-DoS) - ✅ Migración a
html.escape(..., quote=True)para atributos
Code Quality:
- ✅ Nuevo módulo
network/services/port_labels.py(fuente única de_port_labely_get_ports) — Regla 2 - ✅ 12 tests nuevos en
tests/api/test_network_sa5.py(autorización, XSS, inyección)
Sin migraciones requeridas.
Datos de auditoría
- Workflow:
.claude/workflows/auditoria-suprema-network-sa5.js(219 LOC, motor reducido 3 finders → dedup → verif adversarial escalonada) - Finders: 3 slices (API connections, report generator + port suggestion, port config readers)
- Fase Dedup: consolidó duplicados entre finders
- Fase Verify: escalonada (ALTA=3 lentes, MEDIA=2, BAJA=1) — 18/51 confirmados tras votación
Cierre del dominio network
Con esta auditoría el módulo network queda 100% auditado y rectificado (SA1-SA5):
- SA1: credentials, host-key, discovery → [ref: incident—20260515—auditoria-sa1-red-network]
- SA2: SNMP readers, SSH (TOFU/keys) → [ref: incident—20260516—auditoria-sa2-rojo]
- SA3: profiles (discovery API), device config reader → [ref: incident—20260517—auditoria-sa3-device-profiles]
- SA4: topology visualization, diagrama JSON → [ref: incident—20260603—auditoria-sa4-topology-xss]
- SA5: port connections, cable report (ESTA) ← Cierre
Véase también
- [[feature—network—auditoria-sa5-cierre-network]]
- [[entity—network—service—port-labels]]
- [[entity—network—model—port-connection]]
- [[entity—network—endpoint—cable-report]]
- [[concept—saas—multi-tenancy]]