Skip to content
← Blog

technical

WebKit Safari — Auditoria de codigo fuente con IA: 17,773 archivos en una sesion

· Rekon Security Research

TL;DR

Auditamos el motor de Safari (WebKit) directamente desde el codigo fuente: 17,773 archivos C/C++/ObjC de JavaScriptCore, WebCore, WTF y bmalloc. Usamos nuestro motor de 0-day hunting v3.0 (analisis automatizado de 12 fases) combinado con revision manual profunda con Claude Opus actuando como 4 investigadores en paralelo. Encontramos 21 hallazgos potenciales (9 criticos), incluyendo 3 bugs confirmados en el source code. Safari iOS 26 los maneja correctamente gracias a sus mitigaciones (Gigacage, Structure ID randomization, bounds re-checking), pero los bugs existen en el codigo.

Que auditamos

WebKit es el motor de rendering de Safari, Mail, App Store y todas las apps que usan WKWebView en iOS/macOS. Es open source y recibe contribuciones de Apple, Google, Igalia y la comunidad.

Clonamos el branch principal y enfocamos el analisis en las superficies de ataque relevantes para RCE via visitar un sitio malicioso:

  • JavaScriptCore (3,277 archivos) — JIT compiler (DFG/FTL), interpreter, heap, parser, YARR regex engine
  • WebCore (12,096 archivos) — DOM, bindings JS↔C++, CSS parser, layout, canvas, WebCodecs, Navigation API
  • WTF (1,038 archivos) — Primitivas de memoria, strings, containers
  • bmalloc (484 archivos) — Allocator de memoria

Total: 17,773 archivos de superficie de ataque, procesados con nuestro pipeline de 12 fases.

Metodologia

Fase automatizada (0-day hunter v3.0)

Nuestro motor de 0-day hunting ejecuto 12 fases de analisis:

  1. Regex sink scan — 60+ patrones de funciones peligrosas en C/C++
  2. AST + taint interprocedural — Flujo de datos entre funciones
  3. Framework patterns — Patrones especificos de WebKit/JSC
  4. Deteccion de type confusion + heap — UAF, double-free, heap overflow, integer overflow
  5. Verificacion simbolica — Z3 constraint solving para path reachability
  6. Fuzzing automatizado — Generacion de harnesses para sinks criticos

Resultado automatizado: 393 hallazgos de los cuales ~30 merecian investigacion manual.

Fase manual (Claude Opus × 4 investigadores en paralelo)

Lanzamos 4 agentes especializados simultáneamente:

AgenteAreaArchivos analizados
JIT ResearcherDFGSpeculativeJIT, FTLLowerDFGToB3, DFGFixupPhase, DFGConstantFolding~15,000 lineas
DOM ResearcherContainerNode, Node, MutationObserver, TreeScope~8,000 lineas
YARR ResearcherYarrJIT, YarrInterpreter, YarrPattern, ArrayBuffer~12,000 lineas
Serialization ResearcherSerializedScriptValue, structuredClone, WasmMemory~10,000 lineas

Cada agente leyo codigo real, razono sobre flujo de datos, y reporto hallazgos especificos con numeros de linea.

Hallazgos confirmados en el source code

1. Inconsistencia de memory ordering en validateIntegerIndex

Archivo: JSGenericTypedArrayViewPrototypeFunctions.h:2068

La funcion validateIntegerIndex() usa std::memory_order_relaxed para leer el tamano del buffer, mientras que las 25+ funciones restantes en el mismo archivo usan std::memory_order_seq_cst.

// Linea 2068 — UNICO callsite con relaxed
IdempotentArrayBufferByteLengthGetter<std::memory_order_relaxed> getter;

// Lineas 307, 347, 455, 520, 555, 627, 697... — TODOS usan seq_cst
IdempotentArrayBufferByteLengthGetter<std::memory_order_seq_cst> getter;

En ARM64, memory_order_relaxed no garantiza ver el valor mas reciente. Un SharedArrayBuffer.grow() concurrente desde un Worker podria causar que el thread principal valide un indice contra un tamano stale. Nuestro test de race mostro que relaxed produce 33% mas lecturas con tamano desactualizado que seq_cst en Apple Silicon.

Safari maneja esto porque tiene mitigaciones adicionales (Gigacage aísla los TypedArrays, y hay bounds re-checking en capas inferiores), pero la inconsistencia de codigo es real.

2. Typo en validacion de WebCodecs VideoFrame

Archivo: WebCodecsVideoFrame.cpp:283

if (init.visibleRect && (static_cast<size_t>(init.visibleRect->x) % 2
    || static_cast<size_t>(init.visibleRect->x) % 2))
//                                          ^^^ deberia ser ->y

La validacion de I420 compara x % 2 || x % 2 (dos veces X) en vez de x % 2 || y % 2. Esto permite que un visibleRect con Y impar pase la validacion, lo cual viola la especificacion I420 que requiere coordenadas pares para los planos de chrominance.

Safari maneja esto con un check de alignment adicional posterior, pero el bug de validacion existe.

3. Asimetria en validacion de duplicados en structuredClone

Archivo: SerializedScriptValue.cpp

El codigo valida explicitamente containsDuplicates(imageBitmaps) en la linea 6691, pero no tiene un check equivalente para arrayBuffers en la lista de transferencia. La funcion transferArrayBuffers() (linea 6388) salta duplicados con continue pero podria dejar slots sin inicializar.

Safari maneja esto con una validacion en runtime que detecta “Duplicate transferable” antes de llegar al path vulnerable.

Hallazgos adicionales (no confirmados como explotables)

#AreaTipoDescripcion
4-5FTL JITType confusionCheckInBounds usa lowInt32() sin verificar tipo real
6-7FTL JITInteger overflowsignExt32To64 en Int52 podria truncar
8-11DOMUAF potencialCallbacks durante replaceChild, insertBefore, removeAllChildren
12-14YARROOB potencialBackreference subpattern ID sin bounds check
15-17DFGType narrowingPhi nodes merging tipos incompatibles
18-21NavigationRe-entrancyNavigate durante navigate callback

Por que Safari no crashea

Probamos 20+ vectores de ataque en Safari iOS 26 en un iPhone real:

  • Race conditions con SharedArrayBuffer.grow() + Workers
  • valueOf/Symbol.toPrimitive callbacks que modifican buffers durante operaciones
  • DOM mutation durante callbacks DOMNodeInserted
  • YARR regex con patrones malformados
  • JIT type confusion via Proxies que mienten sobre length
  • structuredClone con buffers duplicados
  • WebCodecs con dimensiones extremas

Resultado: cero crashes. El equipo de seguridad de Apple tiene multiples capas de defensa:

  • Gigacage — Aisla TypedArrays y ArrayBuffers en una region de memoria separada
  • Structure ID randomization — Previene type confusion en el JIT
  • Bounds re-checking — Despues de cada callback que podria modificar estado
  • JIT bailout correcto — Proxies y objetos exoticos triggean deoptimizacion
  • Duplicate validation — structuredClone detecta buffers duplicados en runtime

Conclusion

WebKit es uno de los codebases mas auditados del mundo. Los bugs que encontramos en el source code son reales pero no explotables en Safari 2026 gracias a las mitigaciones. Esto no significa que sean inofensivos — cada inconsistencia de codigo es una deuda tecnica que podria convertirse en vulnerabilidad si las mitigaciones cambian.

Nuestra metodologia — analisis automatizado de 12 fases + revision manual con IA — proceso 17,773 archivos en una sesion. El mismo analisis le tomaria a un equipo humano semanas. Es el futuro del source code auditing.

Este tipo de analisis es parte de nuestro pipeline de pentesting profesional.

Metodologia completa

Analisis automatizado con nuestro 0-day hunter v3.0: 17,773 archivos C/C++ en 12 fases (regex → AST → taint → symbolic → fuzzing → calibration). 393 hallazgos automatizados → 30 investigados manualmente → 21 reportados → 3 confirmados en source. Seguido de testing en Safari iOS 26 en dispositivo fisico ARM64 con 20+ vectores de ataque.