# HTTP method override vence la revisión por método

La revisión basada en el método no es segura cuando quien revisa solo ve la línea de petición. Una petición puede llegar como `POST`, llevar `X-HTTP-Method-Override: DELETE` y alcanzar un controlador de borrado después de que un middleware cambie el método. Si una pantalla de aprobación, una regla de pasarela, una comprobación de autorización o un registro de auditoría la clasifica como un POST corriente, ha revisado el envoltorio y ha pasado por alto la acción.

Este comportamiento no es un truco del protocolo HTTP que entiendan todos los servidores. Es una convención de la aplicación, y por eso resulta fácil ignorarla. El soporte cambia según el framework, el orden del middleware, la ruta y el despliegue. La respuesta correcta no consiste en asumir que cada POST es destructivo en secreto. Hay que descubrir dónde se aceptan sustituciones, resolverlas antes de cualquier decisión de seguridad y rechazar la ambigüedad.

## El método en la red y el método efectivo son hechos distintos

Una pila que admite sustituciones debe registrar dos métodos: el de la línea de petición HTTP y el que la aplicación usa finalmente para enrutar. Los llamo método de transporte y método efectivo. Suelen coincidir. El caso peligroso aparece cuando un intermediario aprueba o filtra el primero y un componente posterior enruta según el segundo.

RFC 9110 dice que el token de método es la fuente principal de la semántica de una petición. Define POST como procesamiento específico de un recurso, mientras que DELETE pide al servidor de origen que elimine la asociación entre el recurso objetivo y su función actual. El RFC no normaliza `X-HTTP-Method-Override`. Ese encabezado pertenece a una familia de convenciones de compatibilidad creadas para clientes o intermediarios que solo podían usar GET y POST.

El software habitual aún implementa la convención. El middleware `method-override` de Express lee por defecto `X-HTTP-Method-Override` en un POST. Cuando acepta el valor, cambia `req.method` y conserva el anterior en `req.originalMethod`. ASP.NET Core ofrece middleware de sustitución cuyo encabezado predeterminado también es `X-HTTP-Method-Override`. `HiddenHttpMethodFilter` de Spring toma otro camino: lee un parámetro de formulario `_method` en POST y permite PUT, DELETE y PATCH.

Estos detalles aclaran una distinción que los equipos suelen mezclar. «La pasarela permitió POST» describe el transporte. «La aplicación ejecutó DELETE» describe el comportamiento. Una decisión de aprobación o acceso necesita el segundo dato. Si el componente que decide no puede calcular el método efectivo, debe rechazar las señales de sustitución en vez de clasificar en silencio por el verbo exterior.

El soporte del framework no demuestra por sí solo que exista exposición. Una aplicación Express debe instalar y ordenar el middleware. Una aplicación ASP.NET Core debe añadirlo. Una aplicación Spring debe habilitar y colocar el filtro. La configuración desplegada, incluidos los proxies inversos y el middleware específico de ciertas rutas, decide el resultado. Revisar el código ofrece candidatos; una prueba que compruebe el estado aporta pruebas.

## Un POST aprobado puede llegar al controlador DELETE

Una escritura tunelizada se cuela cuando los componentes no coinciden sobre qué representación de la acción manda. Pensemos en un agente que propone esta petición a una API de proyectos:

```http
POST /v1/projects/42 HTTP/1.1
Host: api.example.test
Authorization: Bearer [injected outside the agent]
X-HTTP-Method-Override: DELETE
Content-Length: 0
```

La capa de aprobación la etiqueta como «POST /v1/projects/42» y aplica una regla que permite POST en esa sesión. Un proxy inverso reenvía el encabezado desconocido. RFC 9110 exige en general que un proxy reenvíe campos desconocidos salvo que su configuración los bloquee o transforme. Dentro de la aplicación, el middleware cambia el método antes del enrutamiento. El router elige el controlador DELETE y el proyecto desaparece.

Este fallo no necesita una comprobación de autorización DELETE defectuosa. La aplicación puede autorizar correctamente a esa identidad para borrar. El defecto aparece antes: una persona o un revisor automático aprobó una acción materialmente distinta porque su clasificador ignoró una entrada admitida. La misma división puede afectar a un firewall de aplicación, un limitador de frecuencia, un control CSRF, las métricas y los registros de acceso.

El orden del middleware determina qué control ve cada dato. La documentación de Express es directa: la sustitución debe ejecutarse antes que cualquier middleware que necesite conocer el método. Es un consejo correcto para el enrutamiento y la lógica CSRF dentro de un proceso. No repara una pasarela externa que ya tomó una decisión mirando la línea de petición.

Hay otro fallo más discreto. El registro del perímetro dice POST, el de la aplicación dice DELETE y quien investiga los trata como peticiones sin relación. Un identificador compartido puede unirlos, pero solo si ambos lados lo conservan y el equipo compara los campos de método. Un único registro normalizado de la acción da menos pie a errores.

No deduzcas el impacto solo por la palabra DELETE. RFC 9110 señala que DELETE quita la asociación entre un recurso y su función actual; la destrucción y la liberación de almacenamiento dependen de la aplicación. Un endpoint DELETE puede archivar, desactivar, poner trabajo en cola o borrar datos. Revisa la consecuencia real de la ruta, no una definición genérica del verbo.

## Prueba el endpoint con una matriz controlada

La prueba fiable compara el estado resultante de métodos nativos, encabezados de sustitución y convenciones de parámetros sobre un recurso desechable. Ejecútala en preproducción o contra un fixture preparado para pruebas destructivas. Usa una identidad con los permisos reales del llamante y vuelve a crear el fixture antes de cada caso para que un borrado no contamine el siguiente resultado.

Empieza con un POST de control sin sustitución. Registra el estado HTTP, el cuerpo y el estado del fixture. Envía después un DELETE nativo. Así confirmas que la ruta existe y que la identidad puede ejercerla. Repite por último el POST con cada convención. Una prueba mínima de encabezado es:

```sh
BASE='https://staging.example.test'
ID='override-probe-17'

curl -sS \n  -D response.headers \n  -o response.body \n  -w 'case=x-http-method-override outer=POST status=%{http_code} bytes=%{size_download}
' \n  -X POST "$BASE/v1/projects/$ID" \n  -H 'Authorization: Bearer test-token' \n  -H 'X-HTTP-Method-Override: DELETE'

curl -sS \n  -o state.body \n  -w 'verify=read-after-request status=%{http_code} bytes=%{size_download}
' \n  -H 'Authorization: Bearer test-token' \n  "$BASE/v1/projects/$ID"
```

La salida tiene a propósito una forma estable que CI puede analizar:

```text
case=x-http-method-override outer=POST status=204 bytes=0
verify=read-after-request status=404 bytes=71
```

El ejemplo ilustra una sustitución que borró el fixture; no es un estado universal. Algunas API devuelven 200 con un documento, 202 para un borrado en cola o una representación todavía legible tras un borrado lógico. Define el éxito según el contrato de tu aplicación.

Usa una matriz, no una secuencia improvisada. El control es POST sin sustitución y debe producir la conducta normal de POST. El caso nativo es DELETE sin sustitución y establece la conducta documentada. Envía luego POST con `X-HTTP-Method-Override: DELETE`, `X-HTTP-Method: DELETE` y `X-Method-Override: DELETE`. Termina con `?_method=DELETE` en la consulta y `_method=DELETE` en un formulario. Cada fila debe ajustarse a tu diseño explícito o fallar sin cambiar el estado.

La guía de pruebas web de OWASP nombra esos tres encabezados y aconseja repetir peticiones con ellos cuando se rechaza un método restringido. Yo iría más allá de comparar estados, porque la diferencia puede venir de la validación, el enrutamiento o un intermediario. Comprueba el recurso, su versión y cualquier trabajo en cola tras cada intento.

Si controlas la pila, captura observaciones en cada salto: registro del perímetro, evento de aprobación, registro de aplicación, ruta elegida y resultado en los datos. Buscas desacuerdos. Un resultado seguro puede ser el rechazo uniforme o una normalización deliberada seguida de la misma autorización y aprobación que recibe DELETE nativo.

## El código de estado da pistas y el cambio de estado prueba

Un código HTTP no puede demostrar por sí solo que se ejecutó la sustitución. Un 204 seguido de un fixture ausente es una prueba fuerte. Un 200 puede ser la respuesta normal de POST, un recibo de borrado o un error mal codificado. Un 405 puede salir del perímetro antes del middleware mientras otra ruta o tipo de contenido aún lo alcanza.

Construye la aserción alrededor de un recurso canario con identificador único y versión inicial conocida. Antes de la prueba, recupera el recurso y guarda su versión o un resumen. Después, vuelve a leerlo y examina cualquier registro de operación. Para actualizaciones elige un campo inocuo e inequívoco. Para borrados conoce si el producto borra de forma física, lógica o diferida.

Comparar respuestas también ayuda. Guarda el código, ciertos encabezados, el tamaño y un resumen del cuerpo. Compara la petición sustituida con POST simple y DELETE nativo. Si respuesta y estado se parecen a DELETE, tienes una conclusión convincente. Si la respuesta parece POST y el estado cambia como DELETE, la capa de respuesta o registro puede seguir usando el método exterior.

Los redireccionamientos merecen una prueba aparte. Un cliente puede cambiar su conducta al seguir 301, 302, 303, 307 o 308, y las herramientas conservan métodos y cuerpos de forma distinta. Ejecuta primero sin seguirlos y guarda `Location`. Síguelos luego de forma deliberada y captura cada salto. No mezcles redirección y sustitución en un resultado opaco.

Las API asíncronas necesitan más observación, no conjeturas. Si la respuesta entrega un identificador de operación, consúltalo según el contrato. Si no hay referencia duradera, examina la cola o el registro en preproducción. Marca un caso no concluyente como tal, no como seguro.

Comprueba también el estado negativo. Una sustitución rechazada no debe crear, actualizar, archivar, encolar, enviar correo ni emitir un webhook privilegiado. Un 4xx limpio puede engañar: un componente posterior pudo confirmar un efecto antes de que otro rechazara la respuesta. Instrumenta el fixture para detectar ese orden.

## Las variantes y la ambigüedad pertenecen a la misma prueba

Probar solo la grafía canónica omite código de compatibilidad y desacuerdos entre analizadores. Los nombres habituales son `X-HTTP-Method-Override`, `X-HTTP-Method` y `X-Method-Override`, pero una aplicación puede definir un lector propio. Consultas y formularios pueden llevar `_method`, y las integraciones antiguas usan nombres asociados a un proveedor o framework.

Las mayúsculas del encabezado no constituyen otra convención. RFC 9110 dice que los nombres de campo no distinguen mayúsculas, así que `x-http-method-override` y `X-HTTP-Method-Override` son el mismo campo. Un filtro que solo coincide con una grafía es defectuoso aunque la biblioteca normalice nombres.

Los valores duplicados y en conflicto revelan un problema más difícil. RFC 9110 permite combinar líneas repetidas con comas cuando la definición del campo lo permite y pide considerar duplicados incluso para campos que esperan un valor. Los encabezados de sustitución no son campos normalizados con una regla común. Express dice que toma la primera repetición, mientras varios lectores instalados pueden crear precedencia entre nombres distintos.

Añade `x-http-method-override: DELETE` y exige el mismo resultado que con la grafía canónica. Envía dos DELETE idénticos y exige un resultado documentado o rechazo. Envía PUT seguido de DELETE y después valores distintos en dos nombres; rechaza ambos por ambigüedad. Rechaza también `PUT, DELETE`, PATCH nativo con sustitución DELETE salvo contrato explícito, y un encabezado DELETE junto a `_method=PATCH`.

No te limites a DELETE. Prueba PUT y PATCH porque la revisión puede clasificar de forma distinta creación, reemplazo, actualización parcial y borrado. Usa un token no admitido como control negativo. Evita TRACE y CONNECT salvo que el alcance lo permita; activan otra conducta de infraestructura sin mejorar esta conclusión.

Los espacios y las mayúsculas del valor pueden descubrir normalización incoherente. Envía `delete`, ` DELETE ` si el cliente lo permite, y un valor vacío. La regla segura es normalizar solo lo documentado, validar contra un conjunto explícito y rechazar el resto. Elegir en silencio el primer valor analizable recreará el bypass cuando cambie un proxy o una biblioteca.

## Las peticiones de agentes facilitan este punto ciego

Los agentes de IA no crean la debilidad, pero empeoran una revisión incompleta. Pueden componer encabezados arbitrarios, reutilizar ejemplos y reintentar un DELETE fallido como túnel POST sin entender que la segunda forma cruza un límite de aprobación. Una persona ante una tarjeta compacta tenderá a mirar el verbo y la ruta visibles.

Trata cada parte generada por el agente como entrada no fiable, incluidos encabezados que parecen metadatos de compatibilidad. Inyectar credenciales fuera del modelo reduce su exposición, pero no vuelve inocua la operación. Ruta, método, encabezados, consulta y cuerpo elegidos por el agente llegan a un sistema que puede interpretarlos juntos.

Los esquemas de herramientas pueden reducir la ambigüedad antes de crear la petición. Una herramienta HTTP genérica con encabezados libres permite solicitar sustituciones. Una herramienta específica para borrar una ruta puede nombrar la acción y omitir campos de sustitución. Es más fácil de revisar, siempre que no conserve una vía oculta para encabezados extra.

Si necesitas una herramienta genérica, analiza la propuesta antes de mostrarla. El analizador debe usar el mismo inventario y precedencia que el ejecutor. Congela la acción normalizada después de aprobarla. Si un intermediario cambia encabezados después, incluye esa transformación determinista en la acción revisada o resuelve otra vez y pide nueva aprobación.

También importan los reintentos. POST no es inocuo ni idempotente por naturaleza. RFC 9110 lo define ampliamente y muchos endpoints POST crean o cambian datos sin sustitución. La herramienta no puede declarar seguro un reintento solo por el método exterior, ni tratar todo POST como destructivo. Necesita semántica de ruta y método efectivo.

Separa identidades de prueba y producción. Una credencial demasiado amplia hará que todo funcione y ocultará diferencias de autorización. Usa el rol limitado real, confirma decisiones iguales para formas nativas y tunelizadas y registra qué mostró la aprobación humana. Solo hay un fallo de revisión si puedes unir propuesta, presentación, ejecución y estado resultante.

## El primer control debe clasificar la acción efectiva

Toda decisión basada en métodos debe ejecutarse después de un único resolvedor o rechazar todas las entradas de sustitución. Vale para aprobación, autorización, CSRF, restricciones, límites y auditoría. Repetir análisis improvisado en cada control garantiza desacuerdos.

Representa la resolución de forma explícita:

```json
{
  "transport_method": "POST",
  "effective_method": "DELETE",
  "override_source": "header:x-http-method-override",
  "override_value": "DELETE",
  "target": "/v1/projects/42",
  "ambiguous": false
}
```

El resolvedor debe inventariar encabezados y parámetros, recoger todos los valores y rechazar más de un candidato distinto. Solo debe aceptar sustituciones desde métodos exteriores permitidos, normalmente POST. Debe validar contra los métodos intencionados y producir un registro inmutable para los controles siguientes.

Coloca la autorización después y vincúlala con ruta y método efectivo. «¿Puede esta identidad hacer POST aquí?» es insuficiente si POST es un túnel. Pregunta si puede ejecutar DELETE sobre ese recurso en esas condiciones. Aplica la misma autorización al DELETE nativo y al tunelizado.

La pantalla de aprobación debe mostrar primero la consecuencia y ambas formas cuando difieran. `DELETE /v1/projects/42 via POST override` expone la acción sin ocultar el transporte. Guardar el encabezado en un panel de petición sin procesar obliga al revisor a descubrir el riesgo bajo presión.

Si la pasarela no puede reproducir las reglas de la aplicación, no le enseñes un subconjunto. Rechaza cualquier señal conocida antes de aprobar o mueve la aprobación tras una normalización fiable. Una pasarela que entiende un encabezado frente a una aplicación que entiende tres crea cobertura falsa.

Separa resolución y semántica de negocio. El resolvedor puede concluir DELETE; la ruta decide si significa archivar, revocar, separar o borrar. Las operaciones de gran consecuencia requieren descripciones ligadas a la ruta. Normalizar el método es necesario, pero un verbo no describe todos los efectos.

## Quitar un encabezado no basta

Eliminar `X-HTTP-Method-Override` en el proxy solo es seguro si el servicio no admite ningún túnel de forma intencionada. Es popular porque es sencillo y bloquea la primera demostración. Falla si sigue activo otro encabezado, `_method`, una ruta directa al origen o middleware posterior.

La guía de YARP de Microsoft nombra los tres encabezados, dice que se reenvían por defecto y propone una transformación para quitarlos cuando se quiera impedir el bypass. Es un endurecimiento útil. No prueba que el destino ignore parámetros ni cubre tráfico que evita YARP.

Elige uno de dos diseños. Si ningún cliente usa túneles, desactiva el middleware y rechaza todas las señales en el perímetro. Si son necesarios, documenta una sola entrada, elimina o rechaza alternativas, normaliza antes de los controles y prueba formas nativas y tunelizadas como la misma acción.

Haz inventario antes. Busca middleware, envoltorios de petición, `_method`, los tres nombres y asignaciones al método. Revisa grupos de rutas y módulos de compatibilidad antiguos conservados tras actualizaciones.

Examina después la ruta de red. Distribución, balanceador, malla, proxy, servidor y framework pueden normalizar o registrar distinto. Confirma que ninguna ruta pública evita el rechazo. Tampoco confíes en encabezados controlados por el llamante solo porque el tráfico del agente sea interno.

Quitar soporte puede romper clientes y por eso se aplaza. Mide uso registrando presencia, sin secretos ni cuerpos completos. Anuncia el retiro, falla claramente en pruebas y elimina a la vez soporte y regla del perímetro. Mantener compatibilidad sin documentar cuesta más que migrar a quienes aún la usan.

## Los registros necesitan ambos métodos

Una auditoría debe guardar método de transporte, método efectivo, fuente, valor normalizado, ruta, identidad, recurso, decisión, respuesta y resultado. Sin ambos métodos no se reconstruye por qué POST alcanzó DELETE. Sin resultado solo consta intención.

Registra también rechazos ambiguos. Un conflicto importa aunque no llegue al controlador. Guarda nombres y tokens normalizados, no credenciales ni cuerpos ajenos. Limita y escapa valores inválidos para impedir que caracteres de control falsifiquen líneas.

Une capas con un identificador creado en el primer salto fiable. Sustituye o aísla cualquier identificador externo. Perímetro, resolvedor, aprobación, aplicación y trabajador asíncrono deben llevar el mismo para seguir una acción sin depender de horas.

Nombra los campos con precisión. `method` invita a significados distintos. Usa `transport_method` para la línea y `effective_method` para la acción. Mapea `originalMethod` deliberadamente en vez de asumir que significa lo mismo en todos los frameworks.

Sallyport ejecuta la llamada HTTP del agente sin entregarle la credencial y la registra en Activity. Esa separación no hace segura una sustitución; la revisión aún debe clasificar el método efectivo antes de ejecutar.

La resistencia a cambios importa tras una ejecución autónoma. Un registro encadenado con hashes permite detectar ediciones, pero no recupera semántica ausente. Registra la acción normalizada al decidir, no mediante una tarea posterior que infiera.

El panel debe sacar a la vista discrepancias. Contar `transport_method != effective_method` por servicio y fuente revela tráfico inesperado. Alerta ante fuentes nuevas, ambigüedad y métodos destructivos cuya aprobación solo guardó el método exterior.

## Una prueba de regresión debe cerrarse con seguridad

La corrección duradera es una prueba contractual sobre el camino desplegado que falle si una sustitución no aprobada cambia estado. Una prueba unitaria no detecta una regla de proxy borrada, middleware reordenado o una nueva entrada.

Define el resultado de cada fila. Si el túnel está desactivado, toda señal debe dar un 4xx documentado y no cambiar el fixture. Si se admite una convención, su DELETE debe coincidir con el nativo en autorización, aprobación, ruta y auditoría. Conflictos y tokens desconocidos deben fallar antes de efectos.

Incluye estas aserciones:

- la aprobación nombra el método efectivo;
- forma nativa y tunelizada reciben la misma autorización;
- las entradas rechazadas no cambian versión ni contadores;
- los registros tienen ambos métodos bajo un identificador fiable;
- el acceso directo al origen no omite la normalización.

Ejecuta la suite cuando cambien proxy, middleware, autenticación, aprobaciones, rutas o herramientas. Una ejecución nocturna detecta deriva y una puerta de publicación detecta cambios deliberados. Aísla el fixture de los datos humanos.

Trata cada nueva convención como cambio de seguridad, aunque el framework la llame compatibilidad. Exige responsable, necesidad, precedencia, método exterior permitido, conjunto efectivo y criterio de retirada. De otro modo, una línea de middleware amplía en silencio las acciones que los controles deben entender.

El sistema limpio usa una descripción de acción desde la entrada hasta el resultado. Si dice POST en la red y DELETE en la aplicación, la diferencia debe aparecer antes de que una persona o componente diga sí. Después solo queda reconstruir el incidente.
