Back to Blog

~$320M perdidos: exploits en Liquid Network y Symbiosis | BlockSec

Code Auditing
17 de septiembre de 2026
15 min read
Key Insights
  • Este informe cubre 2 incidentes de seguridad que suman aproximadamente $320M en pérdidas en la Liquid Network, una sidechain de Bitcoin, y Symbiosis, un puente de Bitcoin desplegado en BNB Smart Chain, Ethereum y Rootstock. El exploit de Liquid Network representó más del 99% del total, mientras que Symbiosis representó un estimado de $770K.

  • En ambos casos, la verificación que debía haber detenido la falsificación se ejecutó e informó éxito mientras certificaba algo incorrecto. Un nodo de Liquid devolvió true para una prueba de rango que nunca examinó, porque un veredicto para una prueba diferente había quedado registrado bajo la misma clave de caché. Los firmantes de Symbiosis produjeron una firma válida sobre un monto de acuñación que su propio decodificador del lado de Bitcoin había calculado a partir de campos controlados por el depositante.

  • El valor de un saldo falsificado depende de la salida, no de su valor nominal. Casi la totalidad de los 4,000 L-BTC no respaldados de Liquid salieron a través del peg de doble vía como bitcoin real, y se movieron ~$320M; el syBTC que Symbiosis acuñó ascendió a más de dos mil veces el suministro de bitcoin, pero los pools a través de los cuales debía venderse contenían 11.26 syBTC, y la pérdida para los proveedores de liquidez y los usuarios ascendió a un estimado de 9.97 BTC.

Durante la semana pasada (2026/09/07 - 2026/09/13), observamos 2 incidentes de seguridad con una pérdida total estimada de aproximadamente $320M.

Fecha Incidente Tipo Pérdida Estimada
2026/09/06 * Liquid Network Construcción Defectuosa de Clave de Caché ~$320M
2026/09/11 Symbiosis Validación Defectuosa de Depósito Fuera de Cadena ~$770K

*El incidente de Liquid Network ocurrió el 6 de septiembre y no fue cubierto en el informe de la semana pasada. Se incluye aquí para completar la información.

El Mejor Auditor de Seguridad para Web3

Valide el diseño, el código y la lógica de negocio antes del lanzamiento

Destacado de la Semana: Liquid Network

El incidente de Liquid Network fue seleccionado por su sutil mecanismo de colisión de clave de caché y las pérdidas sustanciales que causó. Al elaborar una transacción cuyos datos de validación redividían los bytes de una transacción anterior, el atacante logró que se devolviera un resultado de validación en caché para una prueba que nunca fue verificada.

El 2026/09/06, Liquid Network, una sidechain de Bitcoin, fue explotada por aproximadamente $320M [1]. Una colisión en la caché de validación de rangeproof de Elements, el software de nodo que ejecuta Liquid, permitió que un veredicto valid registrado para una salida fuera devuelto para una segunda salida, completamente diferente, cuya prueba fue por lo tanto aceptada sin haber sido nunca examinada. El atacante usó esto para crear 4,000 L-BTC que ningún bitcoin respaldaba, y luego los retiró a través del peg-out ordinario de la red. Al día siguiente se devolvieron 3,400 BTC a la federación, dejando aproximadamente 598.5 BTC en manos del atacante [2].

Contexto

Liquid Network es una sidechain de Bitcoin construida sobre Elements, una plataforma blockchain de código abierto derivada del código base de Bitcoin. Existe para mover bitcoin de forma más rápida, más económica y más privada de lo que permite la cadena principal. El bitcoin cruza entre las dos redes a través de un peg bidireccional: en un peg-in, un usuario bloquea BTC con la federación de la red, un grupo fijo de organizaciones verificadas que custodian conjuntamente los fondos del peg, y recibe una cantidad igual de L-BTC; en un peg-out, el usuario destruye L-BTC y la federación libera el BTC correspondiente. Los bloques de Liquid no se minan. Un conjunto rotativo de los nodos funcionarios de la federación los propone, y un umbral de firmas de la federación los finaliza.

Al igual que Bitcoin, Liquid rastrea los fondos como salidas de transacción no gastadas en lugar de saldos de cuenta. Una transacción nombra salidas no gastadas existentes, las desbloquea y crea nuevas salidas, y el valor que crea debe ser igual al valor que consume. Cada salida lleva un script de bloqueo, su scriptPubKey. Una salida cuyo script comienza con OP_RETURN nunca puede gastarse; existe para transportar datos, y un peg-out se expresa exactamente como ese tipo de salida.

Liquid también oculta los montos por defecto. En lugar de escribir una cifra en una salida, escribe un compromiso de Pedersen a esa cifra. Los compromisos son aditivos, por lo que un nodo puede confirmar que las entradas y salidas de una transacción están equilibradas sin conocer ninguno de los valores involucrados. Esa propiedad funciona en ambos sentidos: un compromiso puede igualmente ocultar un valor que se comporta como negativo, lo que permitiría que las salidas de una transacción excedan sus entradas y aun así se equilibren. Por lo tanto, cada salida cuyo monto está oculto lleva un rangeproof, una prueba de que el monto comprometido se encuentra dentro de [0, 2^64). Verificar un rangeproof es costoso, y la misma salida se verifica más de una vez — cuando la transacción entra en el mempool, y nuevamente cuando llega en un bloque — por lo que Elements mantiene una caché de las pruebas que ya ha aceptado, indexada por la prueba y los datos contra los que se verificó.

Análisis de la Vulnerabilidad

El defecto está en cómo Elements, el software de nodo que ejecuta cada participante de Liquid, almacena en caché los rangeproofs ya verificados.

CachingRangeProofChecker::VerifyRangeProof() deriva una entrada de caché para la salida que tiene enfrente y, en caso de coincidencia, devuelve éxito inmediatamente sin tocar la prueba:

La entrada proviene de ComputeEntryRangeProof(), que escribe cuatro campos uno tras otro en un único flujo SHA-256 y finaliza el resumen:

Los cuatro campos son el propio rangeproof, el compromiso de Pedersen al monto, el generador de activo que identifica qué activo contiene la salida, y el scriptPubKey, incluido para que una prueba aceptada quede vinculada a un script de bloqueo específico.

Ninguno de los cuatro campos lleva un prefijo de longitud o un separador. El rangeproof y el scriptPubKey varían en longitud; el compromiso de Pedersen y el generador de activo son siempre puntos de 33 bytes. El resumen, por lo tanto, registra únicamente los bytes concatenados, sin nada que marque dónde terminó un campo y empezó el siguiente. Dos conjuntos diferentes de cuatro campos que casualmente se concatenan en el mismo flujo de bytes producen la misma entrada, y el que se valide primero deja atrás un veredicto que el otro recoge. El hasher se inicializa con una sal aleatoria específica de cada nodo, pero la sal se antepone a ambos flujos por igual, por lo que cambia el resumen sin distinguir las dos entradas. El defecto se corrigió en el commit 94000967 [3].

Análisis del Ataque

El siguiente análisis se basa en las transacciones 271147...187ec5 y f24a4b...0a183f, ambas aceptadas por nodos que ejecutaban el código vulnerable.

  • Paso 1: El atacante publicó una transacción cuya primera salida es un OP_RETURN que lleva 67 bytes de datos.

Su scriptPubKey dice 6a 43 — el opcode OP_RETURN seguido de un push de 67 bytes — luego dos valores de 33 bytes y un 6a final. Esos 67 bytes enviados no son datos que esta transacción necesite. Son el compromiso de valor y el generador de activo de una salida que aún no existía. La validación de esta salida almacenó un veredicto valid bajo la entrada correspondiente a sus propios cuatro campos.

  • Paso 2: El atacante entonces presentó la transacción de inflación. Su salida OP_RETURN tiene un scriptPubKey que consiste en el único byte 6a, y su compromiso de valor es exactamente el valor de 33 bytes incrustado en el push de la transacción anterior. Su campo de rangeproof se construyó a partir del rangeproof, el compromiso y el generador de activo de la transacción anterior, seguidos de los dos bytes 6a 43.

Los cuatro campos de esta salida, por lo tanto, se concatenan en el mismo flujo de bytes que los de la primera transacción, redivididos en límites diferentes:

Primer:     P0 │ C0 │ X │ S0,  where S0 = 6a 43 <33-byte C1> <33-byte X> 6a
Inflation:  P1 │ C1 │ X │ S1,  where P1 = P0 ‖ C0 ‖ X ‖ 6a 43  and  S1 = 6a

Both concatenate to:  P0 ‖ C0 ‖ X ‖ 6a 43 ‖ C1 ‖ X ‖ 6a

La caché devolvió el veredicto anterior, y P1 nunca fue verificado — no es en absoluto un rangeproof. C1 compromete un monto pequeño negativo. La otra salida de la transacción, una salida normal de pago a hash de clave pública testigo (pay-to-witness-public-key-hash) hacia la dirección del atacante ex1q7kg...qa2w, llevaba un compromiso positivo grande con un rangeproof genuino, y ambos se compensaron entre sí, de modo que la transacción quedó equilibrada. Dejó 4,000 L-BTC no gastados que ningún bitcoin respaldaba.

  • Paso 3: El atacante realizó el peg-out. Dos transacciones quemaron 3,996.01834922 y 2.65138358 L-BTC a través de salidas de peg-out OP_RETURN ordinarias, 3,998.66973280 L-BTC en total. Los nodos funcionarios que autorizan los peg-outs las validaron con el mismo código vulnerable y liberaron el bitcoin: 3,995.99999857 BTC y 2.49749857 BTC llegaron al atacante en Bitcoin, 3,998.49749714 BTC en total.

La red se pausó y se dividió en dos cadenas mientras se resolvía el incidente [4], y se reanudó con el peg-out inválido rechazado [2]: un explorador de bloques hoy muestra la transacción primer confirmada pero no la transacción de inflación, aunque el bitcoin que liberó ya había salido de la billetera de la federación. Al día siguiente, a las 16:09:25 UTC, el atacante devolvió 3,400.00000000 BTC a la billetera de peg de la federación, conservando el resto, ~598.5 BTC pendientes [2], mientras ambas partes negociaban a través de mensajes incrustados en transacciones de Bitcoin [4].

Conclusión

El atacante no rompió ninguna criptografía ni comprometió ninguna clave. El defecto estaba en cómo la caché de rangeproof identificaba lo que ya había verificado. Su clave concatenaba cuatro campos — dos de ellos de longitud variable — en un único flujo de hash sin nada que marcara dónde terminaba cada campo, de modo que un segundo conjunto de campos podía redividir los mismos bytes y coincidir con la misma entrada. Se devolvió entonces un veredicto valid almacenado para una prueba que ningún nodo había verificado nunca, y una vez que un rangeproof deja de restringir el monto que hay detrás de él, un libro contable confidencial pierde lo único que mantiene sus valores ocultos como no negativos. Una salida elaborada se convirtió en 4,000 L-BTC, y el peg bidireccional los transformó en bitcoin en la cadena principal.

Cualquier identificador derivado de más de una entrada de longitud variable debe comprometerse con los límites entre ellas, ya sea prefijando cada campo con su longitud o hasheando los campos en ranuras separadas de tamaño fijo. Sin eso, la derivación no es inyectiva, y dos entradas distintas pueden confundirse con una sola. El requisito es más estricto allí donde una caché reemplaza a una verificación, porque ahí una coincidencia es una decisión de no ejecutarla.


Escaneo de Seguridad Gratuito

Un análisis de seguridad rápido con nuestro motor de análisis automatizado interno.

Escanear gratis

Más Incidentes Esta Semana

Symbiosis

El 2026/09/11, la ruta de Bitcoin del puente entre cadenas Symbiosis fue explotada en sus implementaciones de BNB Smart Chain, Ethereum y Rootstock, costando a los proveedores de liquidez y usuarios un estimado de 9.97 BTC (~$770K, al precio de ~$77K del 11 de septiembre) [5]. Un código fuera de cadena que decide cuánto bitcoin sintético emitir a partir de un depósito de Bitcoin tomó la identidad del depositante de una parte de la transacción que el depositante controla, permitiendo que el atacante se hiciera pasar por el administrador y redujera la tarifa mínima por debajo de cero; luego restó esa tarifa del depósito sin verificar su signo, de modo que la resta en realidad sumaba.

Contexto

Symbiosis es un protocolo de liquidez entre cadenas que mueve valor entre cadenas mediante el bloqueo y la emisión en lugar de transferir el activo en sí: en cadenas con contratos inteligentes, los tokens de un usuario son bloqueados por el contrato Portal en la cadena de origen, y el contrato Synthesis emite una cantidad igual de un token sintético, un sToken, en la cadena anfitriona; quemar el sToken libera el original [6]. El Bitcoin llega a través de esta ruta como syBTC, un token con 8 decimales que coincide con la unidad más pequeña propia del bitcoin, emitido en BNB Smart Chain, Ethereum y Rootstock y emparejado en pools contra BTCB, cbBTC, WBTC y RBTC [5].

Bitcoin no tiene nada de eso: sin contratos inteligentes, no hay contrato Portal para bloquear los depósitos. En su lugar está el portal — una dirección de Bitcoin designada que cumple el mismo papel. Un depósito es una transacción ordinaria de Bitcoin que le paga, con las instrucciones para la cadena de destino adjuntas como datos. El código fuera de cadena perteneciente al puente lee esos datos para conocer quién está depositando, cuánto, y a dónde debe ir el token sintético, y aplica la tarifa del portal — restada del monto depositado antes de fijar el monto a emitir — cuyo mínimo es un parámetro que establece su administrador.

Nada del lado de Bitcoin es visible para la cadena de destino, por lo que una Red de Relayers transporta la solicitud resultante a través. La solicitud llega a BridgeV2, el punto de entrada en cadena del puente, como una llamada codificada que reenvía a Synthesis. La autorización descansa en una clave MPC: los firmantes del protocolo poseen fragmentos de una única clave privada y producen conjuntamente una firma sobre la solicitud. El punto de entrada para las solicitudes relayeadas lleva un único modificador y no hace nada más antes de despachar la llamada:

Ese modificador calcula el hash de la solicitud y exige que la firma que la acompaña sea válida para la dirección MPC:

Lo que el contrato establece es que la clave MPC firmó la solicitud. El monto que lleva la solicitud se calcula en el lado de Bitcoin.

Análisis de la Vulnerabilidad

El defecto no está en los contratos de la cadena de destino. Está en el servicio fuera de cadena que lee los depósitos de Bitcoin y los convierte en solicitudes entre cadenas. Su código fuente no está disponible públicamente, por lo que el relato a continuación sigue el post-mortem del equipo [5] junto con un informe de auditoría de terceros de 2024 que contiene un fragmento de código que parece relacionado [7].

Dos fallas en la ruta de depósito tuvieron que alinearse, y el post-mortem afirma que ninguna era suficiente por sí sola.

La primera está en cómo se identifica al depositante. Las instrucciones adjuntas a un depósito se decodifican para recuperar quién lo está realizando, y el decodificador tomó esa identidad de una parte de los datos de la transacción que controla quien gasta la entrada. Un depositante podía, por lo tanto, nombrarse a sí mismo como cualquier parte que el protocolo reconociera, incluido el administrador del portal, el rol que establece la tarifa mínima que el portal aceptará.

La segunda está en cómo se aplica esa tarifa. La auditoría de 2024 reportó la línea en decodeWrap() que calcula el monto a emitir restando la tarifa del valor de la salida del depósito:

Value: types.Satoshi(tx.TxOut[idx].Value) - info.PortalFee,

Su hallazgo fue que types.Satoshi es un tipo entero con signo mientras que la estructura info que lleva PortalFee no es confiable y está controlada por el usuario, por lo que el resultado puede volverse negativo y, al serializarse para la cadena de destino como un valor sin signo, se convierte en lo suficientemente grande como para emitir una cantidad arbitraria de bitcoin sintético. La auditoría registró el problema como corregido en ese momento [7]. El post-mortem de 2026 describe el mismo tipo de fallo: la tarifa se restó del depósito sin verificar su signo [5], por lo que una tarifa por debajo de cero aumentaba el depósito en lugar de reducirlo. Nada en la ruta de depósito parece limitar el monto a emitir al bitcoin realmente recibido.

Análisis del Ataque

Doce emisiones falsificadas se ejecutaron en BNB Smart Chain, Ethereum y Rootstock en aproximadamente cuatro minutos [5]. El siguiente análisis se basa en una de ellas, la transacción 0x9a2bc0...21b9b959 en BNB Smart Chain.

  • Paso 1: Haciéndose pasar por el administrador del portal, el atacante bajó la tarifa mínima que acepta el portal a un valor por debajo de cero, de modo que un depósito que declarara una tarifa negativa fuera procesado en lugar de rechazado [5].

  • Paso 2: El atacante depositó 330 satoshis, que aparece como 0x000000000000014a. La solicitud que llegó a BNB Smart Chain llevaba 0x400000000000014a — el mismo valor con el bit para 2^62 activado, 4,611,686,018,427,388,234 unidades base. La diferencia entre ambos es exactamente 2^62, por lo que la tarifa restada de este depósito fue -4,611,686,018,427,387,904 satoshis:

    330 - (-4,611,686,018,427,387,904) = 4,611,686,018,427,388,234

    La solicitud fue firmada y relayeada en esa forma.

  • Paso 3: receiveRequestV2Signed() verificó la firma MPC sobre la solicitud y la reenvió, llegando a metaMintSyntheticTokenBTC(). Esa función resolvió la representación sintética del token real para el ID de la cadena de origen, syBTC, y llamó a synthesize() para el monto firmado completo. Todo se transfirió a la dirección del atacante 0x025122...5d3Ba2: 46,116,860,184.27388234 syBTC.

  • Paso 4: El atacante vendió el token sintético en los pools que lo contenían. Un único swap a través de un pool de Uniswap v4 syBTC/WBTC liquidó 18,446,744,072,845,450,682 unidades base de syBTC, aproximadamente cuatro veces lo que emitió la transacción anterior, y extrajo 4.38897292 WBTC.

Redirigidos, los ingresos de ese swap ascendieron a aproximadamente 137 ether.

El equipo pausó la ruta de Bitcoin, y aproximadamente 15.2 BTC de fondos del portal se movieron a direcciones de reserva en cuestión de horas [5]. Se ofreció una recompensa del 20% de cualquier monto devuelto, abierta hasta el 13 de septiembre [8]. Las demás rutas del protocolo no se vieron afectadas.

Conclusión

No se robó ninguna clave y ningún contrato fue engañado para ejecutar código que no estaba escrito para ejecutar. La firma que verificó la cadena de destino era genuina; lo que autorizaba era un número que el código fuera de cadena ya había producido incorrectamente de dos maneras distintas: primero al leer la identidad del depositante de un campo que el depositante controla, permitiendo que el atacante se hiciera pasar por el administrador del portal y bajara su tarifa mínima por debajo de cero, y luego al restar esa tarifa del depósito sin verificar su signo, de modo que una tarifa negativa aumentaba el depósito en lugar de reducirlo.

Una identidad leída de una entrada no confiable no es una identidad: un rol privilegiado solo puede establecerse mediante algo que el depositante no pueda elegir, como la dirección que efectivamente autorizó la entrada gastada, verificada contra una lista que mantiene el protocolo — no un campo que el depositante es libre de completar. Un valor que se resta necesita límites en ambos lados: se debería exigir que una tarifa esté entre cero y el depósito, y el monto a emitir nunca debería poder exceder lo que la cadena de origen realmente recibió. Cualquiera de los dos límites habría detenido esto por sí solo.

Comience con Phalcon Security

Detecte todas las amenazas, alerte sobre lo que importa y bloquee ataques.

Pruébelo gratis ahora

Referencias

[1] https://x.com/Liquid_BTC/status/2096696272447218108

[2] https://x.com/Liquid_BTC/status/2097404704028545175

[3] https://github.com/ElementsProject/elements/commit/94000967f6dc05b1afd435e79b1bbc597e29f816

[4] https://www.coindesk.com/markets/2026/09/08/white-hat-hackers-return-most-of-usd320m-bitcoin-taken-from-liquid-network

[5] https://x.com/symbiosis_fi/status/2099566361940795831

[6] https://docs.symbiosis.finance/crosschain-liquidity-engine/synthesizing-process

[7] https://github.com/symbiosis-finance/audits/blob/master/Symbiosis%20Relayers%20Network/Symbiosis%20Relayers%20Network%202024%20-%20Decurity.pdf

[8] https://x.com/symbiosis_fi/status/2098442463358718264

Acerca de BlockSec

BlockSec es un proveedor integral de seguridad blockchain y cumplimiento normativo en criptomonedas. Desarrollamos productos y servicios que ayudan a nuestros clientes a realizar auditorías de código (incluyendo contratos inteligentes, blockchain y billeteras), interceptar ataques en tiempo real, analizar incidentes, rastrear fondos ilícitos y cumplir con las obligaciones de AML/CFT, a lo largo de todo el ciclo de vida de protocolos y plataformas.

BlockSec ha publicado múltiples artículos de seguridad blockchain en conferencias de prestigio, ha reportado varios ataques de día cero en aplicaciones DeFi, ha bloqueado múltiples ataques para rescatar más de 20 millones de dólares, y ha protegido miles de millones en criptomonedas.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit