x402 2.29.0: el release que cerró un mes de fixes
Los dos roundups anteriores terminaron con el mismo hallazgo: los fixes estaban en main y en ningún artefacto publicado. El 28 de octubre eso dejó de ser cierto. Esta semana trata de qué se publicó, qué rompe y qué debe hacer un gateway que fija versiones.
Buscamos PRs mergeados en x402-foundation/x402 desde el 23 de octubre 00:00 UTC hasta el 30 de octubre 12:00 UTC. La cuenta supera con mucho la ventana anterior. De esos PRs, 37 son de PhilBot402, 10 de phdargen, 9 de mintlify[bot] (docs) y 5 de lgalabru. Varios son PRs de release, así que el número bruto exagera los cambios de código. El número que importa es otro: un release.
El release, con fechas
El registro de npm fecha @x402/core 2.29.0 el 2026-10-28 18:29:54 UTC. La versión anterior, 2.28.0, es del 29 de septiembre. Son 29 días sin release mientras se mergeaban decenas de fixes.
PyPI muestra x402 2.26.0 subido a las 18:29 UTC del mismo día. La numeración de Python es independiente de npm, así que 2.26.0 en PyPI es la contraparte de 2.29.0 en npm. El módulo Go tiene un tag go/v2.29.0 y su changelog está fechado el 28 de octubre.
No nos fiamos solo del changelog. Desempaquetamos ambos tarballs. En el bundle 2.28.0 de @x402/core, el servidor HTTP no tiene fallback para HEAD ni AfterSettleAbortError. En 2.29.0 la rama HEAD está (if (!matchingRoute && upperMethod === "HEAD")) y la nueva clase de error se exporta. Para estos ítems, "mergeado" ya es "publicado".
Qué llegó a producción
Ítems que cubrimos antes como no publicados y que ahora están en los artefactos:
- Bypass de HEAD (#3796). Un HEAD a una ruta GET de pago ahora se cobra. Reprodujimos el bypass contra 2.28.0 el 16 de octubre: 200, el handler corrió, sin contacto con el facilitator.
- Preflight OPTIONS (#3738). Las rutas sin método ya no responden el preflight CORS de un navegador con 402. Las rutas con clave explícita
"OPTIONS /path"siguen exigiendo pago. - Techo del settlement override (#3338).
resolveSettlementOverrideAmount()ahora aplica el techo dePaymentRequirements.amounten formato raw, porcentaje y dólar. Antes, un override podía resolver por encima del máximo autorizado de un pagoupto. - XSS del paywall (#3855). Se corrige un XSS reflejado al incrustar configuración en el HTML del paywall EVM, SVM y AVM, según el changelog de
@x402/paywall. vde EIP-3009 (#3822). Elvde la firma se normaliza a 27 o 28 antes detransferWithAuthorization. Un signer que codificavcomo 0 o 1 ya no falla on-chain.- RFC 8785 (#3700). La canonicalización de offer-receipt ahora cumple el RFC para tab y salto de línea. Antes, el mismo receipt podía firmar bytes distintos a los de otra implementación. Ver nuestra auditoría de receipts.
Novedad de esta ventana, también en 2.29.0:
Un hook puede cerrar un settle en modo fail-closed
Un hook afterSettle ahora puede lanzar AfterSettleAbortError. El settle se reporta como success: false conservando transacción, monto y payer. Los fallos de persistencia del depósito en batch-settlement EVM lo usan, así que un fallo del store ya no parece un settle exitoso. Otros errores de afterSettle siguen sin ser fatales en TypeScript. El changelog de Python declara la misma regla y anota que Go los registra en el log.
Es la misma dirección fail-closed que describimos en la auditoría de recovery: cuando el dinero ya se movió, el receipt no puede mentir sobre el ledger.
Ítems menores. Los clientes de facilitator y Bazaar ahora limitan el body bufferizado a 1 MiB en verify, settle y supported, y a 4 MiB en páginas de discovery. Un body mayor lanza ResponseBodyTooLargeError y cancela el stream. El body JSON del 402 ahora incluye el motivo del rechazo para clientes no navegador, y el catch-all de settlement de Express devuelve { "error": "settlement_failed" } en vez de {}. Los hooks afterVerify ahora corren cuando verify devuelve isValid: false. El registro de facilitator con varios namespaces conserva un wildcard por namespace CAIP-2.
Qué rompe al actualizar
Es una versión minor y trae cambios incompatibles. Léelos antes de subir la versión.
- zod 4.
@x402/coreahora depende de zod ^4.6.6, para incorporar el fix de GHSA-mrhx-c7xc-m3w5. El changelog dice que no existe un zod 3.x parcheado. Los schemas re-exportados y los resultados deparsePaymentRequired/parsePaymentRequirements/parsePaymentPayloadson zod 4. El código que leeZodError.errorsdebe usar.issues. Los arraysaccepts,itemsde discovery,kindsde supported yresourcesde SIWX ahora rechazan más de 1024 entradas. - IDs de red Algorand. Los genesis hash completos ya no se aceptan como valor de red. Solo funciona la referencia CAIP-2 truncada de 32 caracteres introducida en
@x402/avm2.20.0, para clientes, servidores y facilitators. - Sintaxis CAIP-2. Se rechazan los identificadores de red V2 que no cumplen la sintaxis CAIP-2.
- auth-capture. El SDK EVM de auth-capture pasa al spec propuesto v1.1. Se rechaza
extra.autoCapturey los códigos de error cambian deinvalid_*ainvalid_auth_capture_evm_*. Go sumó el servidor y facilitator de auth-capture en el mismo release. - Toolchain de Go. El SDK de Go ahora exige Go 1.26.10 o superior. Los toolchains 1.24 y 1.25 ya no compilan el módulo.
Python además acota el extra x402[mcp] a mcp<2, porque mcp 2.x eliminó mcp.server.fastmcp.
Solana: negociación de versión antes de transaction v1
Los mecanismos SVM ahora negocian la versión del mensaje de transacción. Los facilitators anuncian extra.transactionVersions en /supported, y el conjunto anunciado es [0]. Los servidores lo copian al 402. Los clientes construyen una versión anunciada o se niegan con unsupported_transaction_version. El cambio anticipa transaction v1 (SIMD-0385). El facilitator SVM upto también puede elegir la versión de las transacciones de claim, cancel y rent-cleanup que construye él mismo. En Go, sin configurar se mantiene v1.
Lo práctico: un cliente que arma pagos Solana a mano ahora tiene un campo que leer antes de firmar.
Qué significa para LLM4Agents
Nuestro gateway cotiza y liquida por llamada, así que está del lado vendedor de estos caminos de código. Tres consecuencias.
Primero, la ventana de exposición se está cerrando, no está cerrada. Todo lo que describimos durante cuatro semanas como "en main, no publicado" ahora está en una versión fijable. Cualquier despliegue que siga en 2.28.0 conserva el bypass de HEAD, el hueco del techo de override y el XSS del paywall. El código mergeado no protegió a nadie hasta el 28 de octubre.
Segundo, la actualización no es un patch bump. El cambio a zod 4 toca todo lugar que lee resultados de parseo. Un gateway que loguea ZodError.errors no registrará nada útil tras la actualización. El cambio de ID de Algorand es un rechazo duro, así que una config vieja falla en runtime, no al instalar.
Tercero, AfterSettleAbortError nos da un lugar limpio para escribir en el ledger. Si nuestro paso post-settle no puede registrar el débito, el comprador debe ver un receipt fallido, no uno exitoso que no podemos contabilizar. Aún no cambiamos nuestro código. Es el diseño que adoptaríamos, no algo que ejecutemos hoy.
Cómo mantenerse en la frontera
- Actualizar en una rama, no in situ. Subir
@x402/corea 2.29.0 con pin, y luego buscarZodError,.errorsy cualquier string de red Algorand. - Re-ejecutar las sondas de bypass. HEAD, OPTIONS y paths con
%2Fcontra un facilitator mock. Un fix es real cuando la sonda pasa de 200 a 402 en el bundle publicado. - Adoptar el hook fail-closed. Conectar nuestro registro de débito a un hook
afterSettleque lanceAfterSettleAbortErrorsi el store falla. - Leer
transactionVersionsen nuestro camino Solana y rechazar todo lo que quede fuera del conjunto anunciado. - Vigilar la cadencia. Un hueco de 29 días es un riesgo. Agregar una alerta de "fix de seguridad mergeado más nuevo que el release fijado" para saber cuándo estamos expuestos.
Una salvedad de método: verificamos los tarballs y los changelogs, no el comportamiento de cada ítem. HEAD es el que reprodujimos nosotros, contra 2.28.0. El resto se apoya en el changelog y el texto de los PRs de los maintainers.
Paga por llamada, con el SDK fijado por ti
LLM4Agents sigue los releases de x402 para que tu agente no tenga que hacerlo.
Registrar agente