Como se destacó en nuestro artículo anterior, más del 30% de los proyectos en el repositorio Awesome Uniswap v4 Hooks[1] presentan vulnerabilidades. Vale la pena señalar que las vulnerabilidades a las que nos referimos aquí son específicas de las interacciones con Uniswap v4. En consecuencia, en este artículo examinaremos la lógica de interacción segura de hooks desde las siguientes dos perspectivas:
- Control de acceso deficiente
- Validación de entrada inadecuada
Para cada categoría, comenzaremos con un análisis de la vulnerabilidad y demostraremos su posible explotación proporcionando la Prueba de Concepto (PoC) correspondiente. A esto le seguirá una discusión sobre posibles estrategias de mitigación.
Control de Acceso Deficiente
En general, las interacciones relacionadas con los hooks de Uniswap v4 pueden clasificarse según si el hook actúa como locker, adquiriendo un bloqueo en el PoolManager para realizar operaciones en los pools. Dos escenarios de interacción principales requieren controles de acceso adecuados:
- Interacción Hook-PoolManager: Esto implica interacciones entre las funciones de callback oficiales y el
PoolManager. Las funciones de callback incluyen ocho callbacks de acción de pool (es decir,initialize,modifyPosition,swapydonate) y el callback de bloqueo (es decir,lockAcquired).
- Interacción Hook-Interna: Esto se refiere a las interacciones que ocurren dentro del contrato hook (actuando como locker).
Las interacciones Hook-PoolManager son relativamente sencillas. Aquí, el hook actúa puramente como un hook, aceptando los ocho callbacks de acción de pool. La lógica en el hook no afecta a los pools relacionados, lo que significa que no hay flujos de fondos entre el hook y los pools. Los parámetros proporcionados por las funciones de callback se utilizan para modificar los almacenamientos necesarios o como parámetros de función importantes. La consideración clave es si los parámetros de callback pueden ser manipulados.
Las interacciones Hook-Internas son algo más complejas. En la práctica, muchos prototipos de hooks hacen más que actuar como hooks puros. Algunos desarrolladores permiten que los hooks proporcionen funciones de gestión de fondos para sus usuarios. Estas funciones pueden no estar implementadas en los contratos hook, pero aún podemos considerarlas colectivamente como hooks en este contexto. En estos casos, un hook acepta fondos de usuarios y realiza operaciones de pool como gestión de liquidez o swaps. Esto significa que el contrato debe adquirir un bloqueo del PoolManager, convirtiendo el hook en un locker.
La Fundación Uniswap ha considerado esta situación e integrado una función en su plantilla de hook. Específicamente, la plantilla BaseHook proporciona la función lockAcquired como el callback de bloqueo, de la siguiente manera:
function lockAcquired(bytes calldata data) external virtual poolManagerOnly
returns (bytes memory) {
(bool success, bytes memory returnData) = address(this).call(data);
if (success) return returnData;
if (returnData.length == 0) revert LockFailure();
// if the call failed, bubble up the reason
/// @solidity memory-safe-assembly
assembly {
revert(add(returnData, 32), mload(returnData))
}
}
Para ejecutar lógica personalizada, lockAcquired acepta bytes de data y realiza una llamada de bajo nivel a sí mismo usando esos data. Los data dependen de la lógica de negocio del hook y pueden ser manipulados por los usuarios, lo que potencialmente conduce a problemas de seguridad debido a las interacciones Hook-Internas desencadenadas por lockAcquired. Tenga en cuenta que el diseño de hooks es tan flexible que no podemos cubrir todos los escenarios posibles en esta situación. Nuestro enfoque principal aquí es el hook que adquiere un bloqueo y sus posteriores interacciones internas. Profundizar en otras posibles lógicas de negocio haría la situación demasiado compleja para esta discusión.
En ambos escenarios, la prioridad es abordar cualquier control de acceso deficiente que pueda conducir a una explotación, dado que estas funciones tienen entidades de interacción claras. En las subsecciones siguientes, examinaremos secuencialmente cada escenario y discutiremos los controles de acceso necesarios para garantizar una lógica de interacción más segura.
Análisis de Vulnerabilidad
Los controles de acceso sirven como soluciones de seguridad altamente eficientes y directas para muchos proyectos. Si una función está diseñada para ser llamada por entidades específicas, debe incorporar control de acceso. El ejemplo más conocido de control de acceso es el contrato Ownable de la biblioteca OpenZeppelin, que requiere que las funciones privilegiadas sean llamadas solo por el propietario del contrato. Es evidente que los dos escenarios que discutimos anteriormente son casos apropiados para este tipo de control.
Interacción Hook-PoolManager: Para interacciones seguras con el PoolManager, los hooks deben aplicar el control de acceso necesario en estas funciones de callback. Específicamente, estos callbacks deberían ser invocables exclusivamente por el PoolManager y no por ninguna otra cuenta. No establecer tales controles puede dejar estas interfaces sensibles expuestas a posibles explotaciones por parte de actores maliciosos.
Más allá de los ocho callbacks de acción de pool, el callback de bloqueo (es decir, lockAcquired), que ejecuta lógica personalizada después de obtener el bloqueo del PoolManager, también necesita abordar este problema.
Interacción Hook-Interna: Las funciones involucradas en las interacciones hook-internas también están diseñadas para ser invocadas por llamadores específicos. Como dijimos antes, este escenario contiene dos fases. Primero, la función lockAcquired del locker es llamada por el PoolManager, lo que indica que la función debe requerir que msg.sender sea el PoolManager. Segundo, el hook despacha la llamada a la función en consecuencia. Según el diseño de BaseHook, se implementa mediante llamadas de bajo nivel al propio hook. Esto indica que esas funciones deben estar definidas como external y limitar que el llamador sea la dirección del hook.
Tomemos uno de los ejemplos listados en el repositorio Awesome Uniswap v4 Hooks, es decir, Stop Loss Order como ejemplo[2]:
Integradas directamente en los pools de Uniswap V4, las órdenes stop loss se publican en cadena y se ejecutan a través del hook afterSwap(). No se requieren bots ni actores externos para garantizar la ejecución.
Examinemos su función de callback afterSwap:

Claramente, la función anterior está diseñada para realizar operaciones sensibles. Sin embargo, debido al control de acceso deficiente, podría ser explotada por actores maliciosos que manipulen los argumentos (por ejemplo, key y params), resultando en comportamientos inesperados. Por ejemplo, el callback afterSwap puede operar bajo el supuesto de que el swap ya ha tenido lugar en el PoolManager. A continuación, podría iniciar acciones para registrar información de estado esencial, como el precio actual o las comisiones de swap recolectadas. Sin embargo, si afterSwap no limita sus invocaciones estrictamente desde el PoolManager, los actores maliciosos podrían falsificar el parámetro params, lo que llevaría a estados registrados sesgados.
Explotación y PoC
Por simplicidad, utilizaremos una PoC básica para ilustrar este problema de control de acceso. En general, el beforeInitialize del hook acepta un parámetro de tipo PoolKey, que debe contener la dirección de este hook en su campo hooks (ya que el PoolManager usará este campo para determinar la dirección del hook a llamar).
La captura de pantalla proporciona una PoC que demuestra la explotación de un hook con control de acceso deficiente, como se ve en DiamondHookPoC [3].
En ausencia de restricciones de acceso en la función de callback beforeInitialize, los actores maliciosos pueden proporcionar un poolKey arbitrario a esta función. El hook no verifica si el hook de este poolKey coincide con la dirección del hook actual.

Si bien es importante señalar que la explotación en este escenario puede no causar pérdidas financieras al hook, no obstante destaca dramáticamente cómo el estado del hook puede ser manipulado a través de funciones de callback desprotegidas.
Cómo Mitigar
Para garantizar la seguridad de las interacciones Hook-PoolManager, tanto los callbacks del hook como el callback de bloqueo deben restringir su accesibilidad exclusivamente al PoolManager.
Afortunadamente, Uniswap v4 proporciona mejores prácticas a través del BaseHook en su repositorio v4-periphery[4].
El BaseHook proporciona el modificador poolManagerOnly para restringir las invocaciones estrictamente desde el PoolManager:
/// @dev Only the pool manager may call this function
modifier poolManagerOnly() {
if (msg.sender != address(poolManager)) revert NotPoolManager();
_;
}
Este modificador puede emplearse eficazmente para aplicar un control de acceso adecuado en los callbacks sensibles del hook y de bloqueo.
Por otro lado, la presencia de las interacciones Hook-Internas requiere que cualquier función significativa que cambie el estado invocada a través del callback lockAcquired, tal como lo especifica el BaseHook, no sea invocable de forma arbitraria.
Para cumplir con este requisito, el BaseHook ofrece un modificador selfOnly. Este modificador confina la accesibilidad de la función declarada al propio hook, prohibiendo que contratos externos invoquen directamente estas funciones sensibles con fines maliciosos.
/// @dev Only this address may call this function
modifier selfOnly() {
if (msg.sender != address(this)) revert NotSelf();
_;
}
En resumen, al heredar de BaseHook, los hooks personalizados pueden aprovechar estos modificadores y callbacks de control de acceso integrados para aplicar un control de acceso adecuado.
Validación de Entrada Inadecuada
El BaseHook en v4-periphery[4] ofrece una solución para una lógica de interacción más segura, que los desarrolladores de hooks pueden aprovechar. Sin embargo, seguimos observando instancias de uso inadecuado que abren nuevas posibilidades para vectores de ataque en los hooks existentes.
Por defecto, los hooks permiten que cualquier pool se registre a través de la función initialize en PoolManager. Sin embargo, si un hook no valida los activos subyacentes en el pool que se registra, los usuarios maliciosos podrían registrar un pool con tokens falsificados, lo que les permitiría reingresar al hook a través de la función transfer de los tokens.
Esta vulnerabilidad es sutil ya que el propio hook puede no ejecutar lógica maliciosa. Sin embargo, cuando el hook llama al PoolManager, las interacciones entre el PoolManager y los activos subyacentes de un pool malicioso podrían potencialmente transferir el flujo de control a un atacante a través de la función take en el PoolManager.
/// @inheritdoc IPoolManager
function take(Currency currency, address to, uint256 amount) external override
noDelegateCall onlyByLocker {
_accountDelta(currency, amount.toInt128());
reservesOf[currency] -= amount;
currency.transfer(to, amount);
}
En esencia, la vulnerabilidad surge de validaciones inadecuadas en el pool registrado con el que los usuarios del hook planean interactuar. Profundizaremos en esta vulnerabilidad utilizando un ejemplo concreto y discutiremos posibles estrategias de mitigación.
Análisis de Vulnerabilidad
Take Profits Hook[5] es un hook listado en Awesome Uniswap v4 Hooks:
En este ejemplo, construimos un hook que permite a los usuarios colocar posiciones de 'take-profit'. Por ejemplo, en un pool ETH/DAI si actualmente 1 ETH = 1500 DAI, podrías colocar una orden take-profit como "vender todo mi ETH cuando 1 ETH = 2000 DAI", que se ejecutará automáticamente.
Echemos un vistazo a la función _handleSwap en este hook. Esta función lleva a cabo un swap para completar las órdenes take-profit después de obtener un bloqueo.
![Figura 3: La función _handleSwap de Take Profits Hook[5]](https://assets.blocksec.com/frontend/blocksec-strapi-online/take_profit_handle_Swap_36133dc1fe.jpg)
Puede notar que esta función no está protegida por ningún modificador de control de acceso. Sin embargo, la línea 250 restringe eficazmente el acceso de modo que esta función solo puede invocarse después de que se haya adquirido un bloqueo del PoolManager. De lo contrario, el poolManager.swap fallaría, ya que el operador no sería el locker más reciente. En otras palabras, _handleSwap debe invocarse en un orden específico, siempre que los pools registrados sean validados. Desafortunadamente, el hook no implementa dicha validación.
Debido a esta implementación deficiente, el hook es susceptible a un ataque de reentrada. Esta vulnerabilidad podría permitir a los atacantes forzar swaps arbitrarios usando fondos depositados por los usuarios.
Explotación y PoC
Específicamente, el ataque puede lanzarse a través de los siguientes pasos:
- El atacante registra un pool malicioso con tokens falsos, especificando el Take Profits Hook como el hook del pool.
- El atacante coloca una orden de stop-profit en el pool malicioso a través del hook.
- El atacante realiza un swap en el pool malicioso, activando el
fillOrderen el callbackafterSwappara completar la orden stop-profit del atacante. - El hook invoca la función
lockdelPoolManagerpara solicitar un bloqueo y llama a la función_handleSwapen el callbacklockAcquired. - En la función
_handleSwap, las transferencias de tokens activan lógica maliciosa en el contrato de token falso, que reingresa a la función_handleSwap. Esto es posible porque_handleSwapes una función externa sin ninguna restricción de accesibilidad. Dado que el bloqueo ya ha sido obtenido, el atacante puede forzar al hook a ejecutar swaps arbitrarios en cualquier pool, siempre que el hook tenga suficientes activos subyacentes. El atacante puede entonces hacer sandwich de los swaps para obtener ganancias a expensas de otros usuarios.
El siguiente diagrama detallado ilustra el flujo del ataque.

Como se mencionó anteriormente, el propio hook no invoca lógica maliciosa. El único error es que el hook no impide que pools con tokens no confiables se registren en el contrato PoolManager. Indirectamente, la lógica maliciosa en el contrato de token falso se invoca a través de operaciones de transferencia de tokens, lo que también es un tipo de llamada externa no confiable.
Cómo Mitigar
Existen tres enfoques viables para mitigar posibles ataques debidos a una validación de entrada inadecuada:
-
Control de Acceso Adecuado. Aprovechando los bloques de construcción del
BaseHook, un hook puede gestionar estrictamente la accesibilidad de las funciones. Esto evita que cuentas arbitrarias invoquen funciones sensibles. -
Bloqueo de Reentrada. En el escenario de ataque anterior, este enfoque puede sin duda prevenir que la lógica de token maliciosa reingrese en las funciones sensibles. Sin embargo, en algunos casos, el diseño del hook requiere que el propio hook sea re-enterable. Específicamente, cuando un hook necesita ejecutar algunas acciones de pool, debería permitir que el
PoolManagerreingrese en sus callbacks para completar estas acciones. Un bloqueo de reentrada puede romper esta funcionalidad prevista. -
Enfoque de Lista Blanca. Esto requeriría que un administrador privilegiado incluya en la lista blanca los pools aprobados en los hooks. El administrador garantiza que los pools en la lista blanca no introduzcan riesgos potenciales. Sin embargo, la limitación es que los usuarios del hook solo podrían ejecutar operaciones en un número limitado de pools aprobados por el administrador a través del hook. Si bien el enfoque de lista blanca mejora la seguridad, restringe severamente la funcionalidad del hook.
Es difícil encontrar una solución perfecta que equilibre la seguridad y la usabilidad para los hooks. Si bien discutimos varios enfoques de mitigación, los desarrolladores deberán considerar cuidadosamente las compensaciones en el diseño de sus hooks. El objetivo debe ser mitigar los riesgos potenciales tanto como sea posible mientras se retiene la funcionalidad prevista. Además, nuestra discusión solo cubre vulnerabilidades que pueden encontrarse en las interacciones específicamente relacionadas con las características de Uniswap v4. Las aplicaciones prácticas serán indudablemente más completas. ¡Asegúrese siempre de entender cada línea de sus contratos y manténgase SAFU!
Conclusión
En este artículo, exploramos las vulnerabilidades que surgen durante la lógica de interacción de hooks, concentrándonos específicamente en dos escenarios: control de acceso deficiente y validación de entrada inadecuada. Presentamos un análisis detallado de vulnerabilidades, ilustramos posibles explotaciones junto con sus PoC, y discutimos posibles estrategias de mitigación. Creemos que estos conocimientos pueden contribuir al desarrollo y uso seguros de los hooks, y guiar futuros esfuerzos en la detección de vulnerabilidades.
Referencias
[2] Stop Loss Order
[3] DiamondHookPoC
[4] v4-periphery
[5] Take Profits



