CreaRack-SL

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:

  1. Broken Access Control sistémico: NINGÚN endpoint usaba require_perm → un usuario readonly podía crear/borrar cableado y descargar el mapa de topología completo. Ahora 11 endpoints gateados.
  2. XSS almacenado en Cable Report HTML: nombres de rack interpolados crudos en diagrama Mermaid con securityLevel:'loose'. Sanado: securityLevel:'strict' + escapado de labels.
  3. Inyección de header y markdown: Content-Disposition malformable desde scope_name; pipes en tablas podían romper/inyectar filas. Sanado con whitelist y escapado.
  4. Duplicación de código (Regla 2): funciones _port_label y _get_ports replicadas en API y service. Extraída a nuevo módulo port_labels.py.

Hallazgos confirmados (18 total)

ALTA (3)

TítuloDimensiónArchivoLíneaPropuestaEffort
Broken Access Control en mutaciones port_connectionsSecuritynetwork/api/port_connections.py324, 468, 540Requerir require_perm(network, edit) en create_connection, create_device_connection, delete_connectionM
Broken Access Control en lecturas de topología y cable reportSecuritynetwork/api/port_connections.py, network/api/cable_report.pymúltiplesRequerir require_perm(network, view) en 6 endpoints de lectura/reportM
XSS almacenado en Cable Report HTMLSecuritynetwork/services/cable_report.py396, 418, 425, 459securityLevel:'strict' en Mermaid + sanitizar nombres de rack/location en labels + escapar bloque mermaid en _md_to_htmlM

MEDIA (6)

TítuloDimensiónArchivoLíneaPropuestaEffort
Header Injection en Content-DispositionSecuritynetwork/api/cable_report.py37Whitelist de chars en scope_name para filenameS
Markdown Injection en tablas del reportSecuritynetwork/services/cable_report.pyformato celdasEscapar | y \n en valores de tablaS
ReDoS en regex de parseo SNMP/SSHPerformancenetwork/services/port_suggestion.py, ssh_reader.pymúltiplesRevisar backtracking en PORT_PATTERNS y regex de parseo Cisco/JuniperM
SSRF en PortConfigReader (defensa en profundidad)Securitynetwork/services/port_config_reader/reader.py30Validar is_private_ip dentro del reader, no confiar ciegamente en callerM
200-con-fallo en read_autoCorrectnessnetwork/services/port_config_reader/reader.py63, 95Distinguir exito real vs. “error al leer” en respuesta (Regla 15)S
datetime.now() naive en cable_reportCorrectnessnetwork/services/cable_report.py238Usar timezone.localtime() (Regla 25)S

BAJA (9)

  • Duplicación de _port_label / _get_ports (Regla 2) → Extraída a port_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 defensivo MAX_CONNECTIONS=20000 ✅
  • ReDoS en _extract_port_key (dato de vecino LLDP/CDP) → Acotado a 128 chars ✅
  • _esc incompleto (falta ') → Migrado a html.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") en create_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_text que elimina <>[]{}|" y acota longitud
  • ✅ Whitelist regex en filename del Content-Disposition (solo [A-Za-z0-9._-])
  • ✅ Escape de | y \n en celdas de tabla Markdown (_cell)
  • ✅ timezone.localtime() para generated_at (Regla 25)
  • ✅ Cap defensivo MAX_CONNECTIONS=20000 con truncado logged
  • ✅ Acotado _extract_port_key a 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_label y _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]]