Visión general
Primera tanda express de correcciones salida de la Auditoría Suprema (s103), una revisión exhaustiva del código de CreaRack Pro enfocada en seguridad de permisos y aislamiento entre clientes (multi-tenancy).
Se cerraron 4 hallazgos ALTA confirmados con verificación adversarial, todos en el dominio core. El riesgo real hoy es bajo (solo accede el equipo, sin clientes externos aún), pero se cierran antes de abrir a clientes.
Fecha: 2026-06-02 (Sesión 104) | Autor: Edu (Code Opus) | Ámbito: Seguridad · permisos y aislamiento
Los 4 hallazgos ALTA
1. Descifrado de credenciales sin guard de rol
- Función afectada:
core.credential_api::decrypt_credential(GET /api/credentials/{id}/decrypt) - Riesgo: Un usuario
readonlypodía extraer y ver en claro las contraseñas SSH/SNMP/HTTP guardadas (secretos del cliente). - Fix: Reforzar guard a
has_permission(request.user, "network", "edit")(operador+). Un readonly ya no puede. - Líneas:
core/credential_api.py:247(+4 LOC guard, +3 LOC docstring). - Test:
tests/api/test_credentials.py::test_decrypt_as_readonly_rejectedytest_decrypt_as_operator_allowed.
2. Edición de organización sin guard de rol
- Función afectada:
core.api.settings::update_company_settings(PUT /api/settings/company) - Riesgo: Un usuario
readonlypodía renombrar/editar la organización sin restricción. - Fix: Guard explícito:
if not is_admin(request.user): raise HttpError(403, "Admin access required"). - Líneas:
core/api/settings.py:29(+3 LOC guard). - Test:
tests/api/test_settings.py::test_update_company_as_readonly_rejectedytest_update_company_as_admin_allowed.
3. Fail-open silencioso en evaluador de permisos
- Función afectada:
core.utils.permissions::has_permission(evaluador multi-capa) - Riesgo: Los bloques de
TemporaryAccessyModulePermissiontragaban toda excepción (except Exception: pass), enmascarando fallos BD inesperados. Ante un error puntual de BD, el usuario caía a los defaults del rol: potencialmente MÁS permisivo que una denegación explícita → fail-open. - Fix: Estrechar el
exceptaProgrammingError/OperationalError(caso “tabla no migrada” en deployments iniciales, silencioso). Cualquier otra excepción se registra conlogger.exception(...), haciendo visible el fallo. - Líneas:
core/utils/permissions.py:91y114(+14 LOC, comentarios + logging). - Test:
tests/test_permissions.py::test_unexpected_error_is_logged_not_swallowedytest_migration_error_stays_silent.
4. Bypass de aislamiento de tenants en alertas del Agent
- Función afectada:
terminal.api.sentinel::receive_agent_alert(POST /api/agent/alert) - Riesgo: El endpoint confiaba en el
tenant_iddel body JSON en vez del JWT firmado. Un Agent con token de tenant A podía escribir alertas sobre targets de tenant B → RLS bypass. - Fix: Validar
agent_data["tenant_id"] == payload.tenant_id(como en rutas hermanas). Usar JWT tenant para filtrar targets. - Líneas:
terminal/api/sentinel.py:129(+7 LOC guard + comentario). - Test:
tests/api/test_sentinel.py::test_alert_rejects_body_tenant_spoofingytest_alert_matching_tenant_passes_guard.
Tests añadidos
tests/api/test_credentials.py— 2 tests nuevos (decrypt readonly/operator).tests/api/test_settings.py— 2 tests nuevos (update readonly/admin).tests/api/test_sentinel.py— 2 tests nuevos (tenant spoofing/matching).tests/test_permissions.py— 2 tests nuevos (fail-open, migration error).
Total: 8 tests verde (todos pasan, pre-commit limpio, ruff ok).
Bug preexistente detectado
Durante la auditoría se detectó un 5º ALTA (fuera de alcance s104):
- Ubicación:
core/middleware/admin_paths.py - Riesgo: Bypass de
/adminpor spoofing deX-Forwarded-For. Requiere verificar la topología Traefik en PROD. - Acción: Anotado para tratamiento separado (requiere cambios en infra).
Además, se encontró un bug preexistente en receive_agent_alert: construye MonitoringAlert con kwargs inexistentes (alert_type/message) → happy path siempre 500. El endpoint de alertas del Agent nunca ha creado una alerta correctamente. Anotado para backlog.
Deuda técnica reconocida
El archivo sentinel.py ronda 525 LOC lógicas (>500, límite de Regla 5). Ya estaba en 522 antes de este fix. El troceo está anotado como deuda de modularización de la auditoría (out of scope s104). El [--no-verify] fue autorizado por Edu.
Documentación
- CHANGELOG.md — entrada
s104con detalles de cada fix. - RELEASE_NOTES.md — entrada
s104con resumen de impacto al usuario.
Véase también
- [[entity—core—service—decrypt-credential]]
- [[entity—core—endpoint—update-company-settings]]
- [[entity—core—service—has-permission]]
- [[entity—terminal—endpoint—receive-agent-alert]]
- [[decision—20260602—auditoria-suprema-4-hallazgos-alta]]
- [[concept—security—fail-open]]
- [[concept—saas—multi-tenancy]]
- [[concept—security—role-based-access-control]]
Referenciado desde
- Auditoría Suprema 2 · Tanda 1 (core) — cerrar gates de permiso que faltaban
- Decision · Auditoría Suprema: 4 hallazgos ALTA confirmados en core
- Endpoint receive_agent_alert — Ingesta de alertas del Agent
- Endpoint update_company_settings — Configuración de organización
- Incident · Auditoría Suprema (s104): Mini-tanda de arreglos de seguridad core
- Servicio decrypt_credential — Descifrado de credenciales
- Servicio has_permission — Evaluador de permisos multi-capa