Cómo difieren los CVEs de memory safety entre Rust y C/C++
¿Por qué seguimos midiendo la seguridad de un lenguaje por cantidad de CVEs si sabemos que ese número depende tanto del tamaño de la base instalada como de cualquier propiedad del lenguaje en sí? Llevó años de debate y un par de papers de NSA y CISA para que el ecosistema tomara en serio la pregunta — y aun así, la respuesta que circula en la mayoría de los hilos es demasiado simple para ser útil.
Mi tesis es esta: la diferencia en CVEs de memory safety entre Rust y C/C++ es real, documentable y técnicamente interesante. Pero convertirla en "migrá todo a Rust" o en "el borrow checker lo resuelve todo" es un error de categoría. El dato útil no está en el titular — está en qué tipo de vulnerabilidades desaparecen, cuáles persisten y bajo qué condiciones el modelo de seguridad de Rust tiene fricciones propias.
El problema real: no todos los CVEs de memoria son iguales
Cuando CISA, NSA o el White House Office of the National Cyber Director publican reportes recomendando lenguajes memory-safe (y lo hicieron de forma pública entre 2022 y 2023), la categoría que apuntan es específica: vulnerabilidades causadas por comportamiento indefinido en la gestión manual de memoria. Use-after-free, buffer overflow, double-free, null pointer dereference no chequeado — la familia clásica de C/C++.
La distinción técnica importa:
| Clase de vulnerabilidad | C/C++ | Rust (safe) | Rust (unsafe) |
|---|---|---|---|
| Use-after-free | Común | Imposible por diseño | Posible |
| Buffer overflow (stack/heap) | Común | Imposible por diseño | Posible |
| Data race en multithreading | Común | Imposible por diseño | Posible |
| Integer overflow | Posible | Debug: panic / Release: wrapping | Igual |
| Logic bugs | Siempre posible | Siempre posible | Siempre posible |
| Unsafe block mal usado | N/A | Posible | Posible |
La tabla no es un benchmark de producción — es un mapa de qué garantías da el compilador de Rust en código safe vs. qué queda fuera de esas garantías. La fuente no es un claim propio: el modelo de ownership y las reglas del borrow checker están descritos formalmente en en GitHub mantiene advisories de seguridad para el ecosistema Rust. Es auditable, tiene categorías por tipo de vulnerabilidad y fecha. Podés correr:
# Instalar cargo-audit si no lo tenés
cargo install cargo-audit
# Auditar dependencias de cualquier proyecto Rust
cargo audit
# Ver advisories activos con detalle
cargo audit --json | jq '.vulnerabilities.list[] | {id: .advisory.id, title: .advisory.title, categories: .advisory.categories}'
El resultado te dice no solo si hay vulnerabilidades conocidas, sino de qué categoría son. Ese dato es concreto y reproducible en cualquier máquina.
2. CVE Details / NVD por CWE
El NVD (National Vulnerability Database) categoriza CVEs por CWE (Common Weakness Enumeration). CWE-119 (buffer errors), CWE-416 (use-after-free) y CWE-476 (null pointer dereference) son las categorías que concentran la mayor parte de los CVEs históricos de proyectos C/C++. Podés filtrar por lenguaje y año en .
Matriz de decisión: cuándo este dato cambia algo y cuándo no
Antes de usar la comparación de CVEs como argumento técnico, pasala por esta checklist:
CHECKLIST: ¿El dato de CVEs de Rust vs C/C++ es relevante para mi decisión?
[ ] ¿El sistema que estoy evaluando tiene C/C++ con gestión manual de memoria?
→ Si no, la comparación es irrelevante para vos.
[ ] ¿La superficie de ataque principal son vulnerabilidades de memoria (UAF, overflow)?
→ Si el riesgo dominante es lógica de negocio o autenticación, Rust no cambia eso.
[ ] ¿Tengo capacidad de revisar unsafe blocks en dependencias críticas?
→ Si no, la ganancia se reduce: importás riesgo opaco igual que en C.
[ ] ¿El proyecto usa FFI extensivo con C?
→ El beneficio del borrow checker se acota a la porción safe del código.
[ ] ¿Estoy evaluando código nuevo vs. migrar código existente?
→ Migrar una base C/C++ grande tiene un costo real de reescritura y periodo de coexistencia.
→ Código nuevo en Rust sobre un dominio bien acotado: el beneficio es inmediato y verificable.
[ ] ¿El equipo tiene experiencia con el modelo de ownership?
→ La curva de aprendizaje del borrow checker es real. Un equipo sin experiencia en Rust
puede introducir más bugs durante la transición que los que evita a mediano plazo.
Para proyectos donde el dominio es computación de bajo nivel, parsing de formatos binarios no confiables, daemons de sistema o componentes de red con alta exposición, el argumento a favor de Rust es sólido y respaldado por evidencia pública. Para un backend de negocio en TypeScript o Java donde el riesgo dominante es inyección, autenticación mal implementada o lógica de permisos rota, el debate de memory safety es casi una distracción.
Esto conecta con algo que también aplica al , y creer que una herramienta resuelve la seguridad de forma holística es la forma más elegante de bajar la guardia donde más importa.
Este artículo fue publicado originalmente en juanchi.dev
SOCIAL SHARE CARD GENERATOR