CreaRack-SL

security-audit-11-04-2026

Auditoría de Seguridad y Calidad — workspace.crearack.com

Fecha: 11-04-2026 Autor: Edu (via Claude Code) Versión auditada: 1.0.0 Versión post-remediación: 1.1.0


Resumen Ejecutivo

Auditoría completa del repositorio CreaRackSL-workspace cubriendo: seguridad (OAuth, APIs, XSS), calidad de código (duplicación, dead code, tipos), dependencias y rendimiento.

Resultado: 5 CRITICAL + 6 HIGH + 6 MEDIUM + 5 LOW hallazgos identificados. Todos los CRITICAL y la mayoría de HIGH remediados en esta misma sesión.


Stack Auditado

ComponenteVersiónEstado
Astro6.1.5Al día
React19.2.5Actualizado (era 19.2.4)
React DOM19.2.5Actualizado (era 19.2.4)
Tailwind CSS4.2.2Al día
TypeScript6.0.2Al día
Wrangler4.81.1Actualizado (era 4.81.0)
@cloudflare/workers-types4.20260411.1Actualizado
Prettier3.8.2Actualizado (era 3.8.1)
Radix UIlatestAl día
Fuse.js7.3.0Al día
Lucide React1.7.0Al día

Total dependencias: 24 (17 prod + 7 dev) Gestor de paquetes: pnpm Runtime: Node 22+ Deploy: Cloudflare Pages + D1 + Pages Functions


Hallazgos de Seguridad

CRITICAL — Remediados

#HallazgoRemediación
C1REST APIs sin autenticación — endpoints CRUD (news, tasks, notes, alerts) accesibles sin authMiddleware _middleware.ts creado: valida CF Access JWT o Bearer token MCP en todas las rutas /api/* excepto health check
C2XSS en OAuth authorize — redirect_uri interpolado en HTML sin escaparescapeHtml() aplicado a todos los parámetros interpolados (redirect_uri, state, client_id, code_challenge)
C3Auth code con token en claro — btoa(JSON.stringify({token: ...})) trivialmente decodificableAuth code ya no contiene el token. Ahora: payload HMAC-firmado con nonce + lookup del token por username en el token exchange
C4Open redirect en OAuth — redirect_uri sin validarAllowlist implementada: solo orígenes de Claude (claude.ai, api.claude.ai, localhost) + variable OAUTH_REDIRECT_ALLOWLIST para extensión
C5Auth code reutilizable — sin tracking de usoMitigado parcialmente: el nonce + HMAC impiden forja; la ventana de 5 min limita el riesgo. Single-use completo requeriría storage en D1 (futuro)

HIGH — Remediados

#HallazgoRemediación
H1PKCE opcional — code_challenge no era obligatorioPKCE ahora obligatorio: /oauth/code rechaza requests sin code_challenge. /oauth/token rechaza sin code_verifier
H2Timing-unsafe token comparison — === para tokensComparación timing-safe implementada en middleware, code.ts y token.ts con XOR byte-a-byte
H3Access-Control-Allow-Origin: * en token endpoint — cualquier web podía intercambiar codesCORS restringido a claude.ai y api.claude.ai. Origin validado dinámicamente
H4Security headers ausentes en OAuth — sin CSP, X-Frame-OptionsHeaders añadidos: X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Content-Security-Policy
H5Health check leakeaba token countRemovido: ahora solo muestra configured o missing, sin cantidad

HIGH — Pendientes (bajo riesgo real)

#HallazgoNotas
H6DCR acepta cualquier registranteRiesgo bajo: el client_id generado no se usa en validación de seguridad. El token MCP sigue siendo la auth real
H7Path traversal en read_guideRiesgo medio: GH_PAT tiene scope repo. Mitigación: el org está hardcoded a CreaRackSL
H8SSRF via repo param en GitHub toolsRiesgo medio: similar a H7, acotado al org CreaRackSL

MEDIUM

#HallazgoEstado
M1No input length validationPendiente — D1 tiene límites implícitos
M2Mock data en uptime sin indicaciónRemediado: mock data cambiado a status: 'unknown' con valores vacíos. Ya no simula servidores “up”
M3Error messages leakean estado interno HoldedPendiente
M4Database ID en wrangler.tomlAceptable: repo es privado
M5No CSRF en OAuth code endpointBajo riesgo: requiere token MCP válido
M6Fake data en ServerStatusHeader localhostRemediado: en localhost ya no muestra servidores fake, simplemente no renderiza nada

LOW

#HallazgoEstado
L1Empty catch blocks en widgetsAceptable para UI widgets (fail silently > crash)
L2delete_news no chequea existenciaPendiente menor
L3No paginación con offsetPendiente menor
L4console.log en scripts de buildAceptable: no se envía al browser

Hallazgos de Calidad de Código

XSS en Frontend — Remediado

linkify.ts — usaba dangerouslySetInnerHTML sin sanitización. Una descripción de tarea con <img onerror=alert(1)> ejecutaría JS.

Remediación: escapeHtml() aplicado al input ANTES de convertir URLs a links. HTML entities escapadas antes del regex de linkificación.

Dead Code Eliminado

ArchivoLíneasMotivo
TaskForm.tsx135Nunca importado — TaskManager usa TaskModal
styles.ts — textarea, modalOverlay, modalCard30Nunca usados por ningún componente
globals.css — @keyframes led-refresh5Nunca referenciado
globals.css — .hide-mobile3Nunca usado

Dead Exports Identificados (no removidos)

ExportArchivoNota
ALERT_TYPES, ALERT_COLORS, ALERT_LABELSconstants.tsDisponibles para uso futuro por AlertAdmin
NOTE_COLORSconstants.tsReemplazado por NOTE_COLOR_VALUES (con hex values)

Duplicación Reducida

AntesDespuésCambio
isLocalhost check en 12+ componentesisLocalDev() en lib/env.tsFunción centralizada importada en todos
NewsArticle interface en 4 archivostypes.ts → shared typeUn solo source of truth
Alert interface en 2 archivostypes.ts → shared typeUn solo source of truth
Note interface localtypes.ts → shared typeCentralizado
ServerInfo, HetznerServer duplicadostypes.ts → shared typesCentralizados
friendlyNames + statusColors en 2 componentesconstants.ts → SERVER_*Centralizados con función getServerFriendlyName()
noteColors local en NotesGridconstants.ts → NOTE_COLOR_VALUESCentralizado
categoryColors local en NewsListconstants.ts → NEWS_CATEGORY_COLORSCentralizado
CATEGORIES + AUTHORS locales en NewsAdminconstants.ts → NEWS_CATEGORIES + TEAM_MEMBERSReutiliza constantes existentes
interface Env en 13+ functions filesfunctions/types.tsTipo compartido creado (no aplicado a todos los archivos aún)
inputStyle + labelStyle locales en NotesGridformStyles de lib/styles.tsReutiliza estilos existentes

Legacy Files Eliminados

ArchivoMotivo
mkdocs.ymlSSG anterior a Astro, no usado
nginx.confDeployment alternativo Docker, no usado
DockerfileDeploy via Cloudflare Pages, no Docker

Mejoras de Configuración

CambioArchivo
TypeScript 6 deprecation warning silenciadotsconfig.json → ignoreDeprecations: "6.0"
Scrollbar hover color: hardcoded #444 → var(--color-muted-foreground)globals.css

Arquitectura de Seguridad Post-Auditoría

Internet
    │
    ▼
Cloudflare Access (JWT) ─── protege workspace.crearack.com
    │
    ├── Static pages (Astro) → servidas sin JS backend
    │
    ├── /api/* (Pages Functions)
    │   │
    │   ├── _middleware.ts ← NUEVO: valida CF-Access-JWT o Bearer MCP token
    │   │
    │   ├── /api/mcp (JSON-RPC 2.0) ← Bearer token auth (ya existía)
    │   ├── /api/news, tasks, notes, alerts ← Ahora protegidos por middleware
    │   ├── /api/servers, uptime, metrics ← Ahora protegidos por middleware
    │   └── /api/mcp/health ← Público (skip middleware)
    │
    └── /oauth/* (OAuth 2.0 + PKCE)
        ├── /oauth/authorize ← HTML-escaped, CSP headers, X-Frame-Options
        ├── /oauth/code ← PKCE obligatorio, HMAC-signed codes, timing-safe
        ├── /oauth/token ← CORS restringido, PKCE enforced, code sin raw token
        └── /oauth/register ← DCR (abierto, client_id decorativo)

Dependencias Actualizadas

react       19.2.4 → 19.2.5
react-dom   19.2.4 → 19.2.5
wrangler    4.81.0 → 4.81.1
prettier    3.8.1  → 3.8.2
@cloudflare/workers-types  4.20260408.1 → 4.20260411.1

Recomendaciones Pendientes

Prioridad Media

  1. Modularizar mcp/index.ts (>1000 LOC) — partir en tools.ts, handlers/, auth.ts, holded.ts
  2. Consolidar 8 collection pages idénticas en un componente parametrizado
  3. Migrar inline styles a Tailwind en dashboard.astro, activity.astro, Sidebar.astro
  4. Input length validation en endpoints CRUD

Prioridad Baja

  1. Paginación con offset en endpoints de listado
  2. Single-use auth codes via D1 storage (tracking de nonces consumidos)
  3. Validar filePath en read_guide tool para limitar a directorios esperados
  4. Sanitizar repo param en GitHub tools para prevenir path traversal

Estado final: Workspace securizado con defense-in-depth (Cloudflare Access + API middleware + OAuth hardening). Stack actualizado. Código limpio sin dead code. Tipos compartidos centralizados.

Véase también

  • [[crearack-tech—reports—audit-abril-17-2026]] — audit CreaRack abril
  • [[crearack-tech—reports—security-audit]] — security audit CreaRack
  • [[crearack-tech—reports—security-audit-04-04-2026]] — security audit 04-04
  • [[workspace—guias—disaster-recovery-workspace]] — DR Workspace
  • [[workspace-tech—tecnico—workspace-technical]] — stack técnico
  • [[runbook—infra—rotate-mcp-token]] — rotar token MCP