
XSS almacenado a través de User-Agent en la Vista de Pedidos del Administrador en PhocaCart
PhocaCart ≤ 6.1.7 — Un atacante no autenticado almacena un payload XSS a través del checkout. Se ejecuta en el contexto del navegador del administrador
PhocaCart 6.1.7 para Joomla almacena la cabecera HTTP User-Agent sin procesar de las solicitudes de checkout en la tabla de pedidos de la base de datos cuando la opción de configuración store_user_agent está habilitada. El valor almacenado se renderiza posteriormente sin codificación HTML en la vista de edición de pedidos del administrador mediante itemText() en Adminview.php.
Un atacante no autenticado puede realizar un pedido con un User-Agent manipulado que contenga un payload JavaScript. Cuando un administrador abre el pedido en el backend, el payload se ejecuta en el contexto del navegador del administrador, lo que permite el secuestro de sesión, el robo de credenciales o acciones administrativas no autorizadas.
La vulnerabilidad requiere que store_user_agent = 1 (no predeterminado) esté habilitada. Debido a que esta opción es una elección deliberada del administrador para recopilar estadísticas del navegador, las tiendas afectadas son aquellas en las que el propietario ha habilitado la función, lo que hace que la explotación sea totalmente silenciosa desde la perspectiva del atacante.
| COMPONENTE | VULNERABLE | PROBADO EN | CORREGIDO |
|---|---|---|---|
| PhocaCart (com_phocacart) | 5.0.0 – 6.1.7 | Joomla 5.4.7 + PhocaCart 6.1.7 + MariaDB 10.6 | 6.1.8 |
Tipo: XSS almacenado (CWE-79) — dirigido al administrador
Autenticación requerida: Ninguna para inyectar. Administrador para activar
Token CSRF requerido: Sí (se requiere el token CSRF estándar de Joomla para el checkout)
Archivo: administrator/components/com_phocacart/libraries/Phoca/Render/Adminview.php:382
Cuando store_user_agent = 1, el método PhocacartUtils::getUserAgent() devuelve $_SERVER['HTTP_USER_AGENT'] sin ninguna sanitización. Esta cadena sin procesar se almacena en #__phocacart_orders (truncada a 200 caracteres — insuficiente para prevenir XSS). Cuando un administrador visualiza el pedido en el backend, itemText() concatena el valor almacenado directamente en la respuesta HTML sin llamar a htmlspecialchars().
Flujo de datos:
Attacker sends checkout request:
User-Agent: <script>alert(document.domain)</script>
utils.php:334 PhocacartUtils::getUserAgent()
└─ return (string) $_SERVER['HTTP_USER_AGENT'] // raw, no sanitization
order.php:413 $d['user_agent'] = substr($user_agent, 0, 200)
└─ INSERT INTO #__phocacart_orders (user_agent) VALUES ('<script>...</script>')
Admin opens order in backend:
edit.php:84 echo $r->itemText($this->itemcommon->user_agent, ...)
Adminview.php:382 '<div class="controls >' . $item . '</div>'
// → NO htmlspecialchars()
→ Browser renders: <div><script>alert(document.domain)</script></div>
→ XSS fires in administrator's browser
ORDER.PHP — FASE DE ALMACENAMIENTO (FUENTE VULNERABLE)
administrator/components/com_phocacart/libraries/phocacart/order/order.php:424
$user_agent = PhocacartUtils::getUserAgent(); // reads $_SERVER['HTTP_USER_AGENT'] raw
$d['user_agent'] = substr($user_agent, 0, 200); // stored in DB unfiltered
ADMINVIEW.PHP:382 — FASE DE RENDERIZADO (SUMIDERO VULNERABLE)
// No htmlspecialchars() applied:
$output .= ' <div class="controls ' . $class . '">' . $item . '</div>' . "\n";
Llamado desde administrator/components/com_phocacart/views/phocacartorder/tmpl/edit.php:84:
echo $r->itemText($this->itemcommon->user_agent, Text::_('COM_PHOCACART_USER_AGENT'), '', 'user_agent');
La función itemText() pasa $item (el valor almacenado de user_agent) directamente a la salida HTML sin codificación, convirtiéndolo en el sumidero principal. Corregirlo a nivel del sumidero protege a todos los llamadores de itemText().
El ataque requiere completar un flujo de checkout completo con una cabecera User-Agent maliciosa. El token CSRF debe obtenerse primero, ya que el controlador de checkout de Joomla lo valida.
En el administrador de Joomla, navegue a Components → Phoca Cart → Options → Main tab → Statistics Options. Establezca Store User Agent Information = Yes y guarde.

El atacante visita el frontend de la tienda para extraer un token CSRF válido de Joomla requerido por el controlador de checkout. El token aparece en el código fuente HTML o en la configuración JavaScript de cualquier página de la tienda.

El atacante añade un producto al carrito a través del endpoint AJAX de checkout utilizando un User-Agent benigno. Esto transiciona la sesión de checkout al siguiente estado.

El atacante envía la información de facturación para avanzar en la máquina de estados del checkout.

El atacante selecciona un método de envío para continuar al pago.

El atacante selecciona un método de pago (p. ej., Contra reembolso).

Paso de inyección crítico. El atacante realiza el pedido final mediante task=checkout.order con la cabecera User-Agent establecida al payload XSS. La tarea checkout.order lee el HTTP_USER_AGENT sin procesar y lo almacena sin escapar en #__phocacart_orders.user_agent.
POST /index.php/shop/checkout HTTP/1.1
Host: TARGET
User-Agent: <script>alert(document.domain)</script>
Content-Type: application/x-www-form-urlencoded
phcheckouttac=1&task=checkout.order&option=com_phocacart&return=&<CSRF_TOKEN>=1
Resultado: Pedido creado. La base de datos almacena user_agent = '<script>alert(document.domain)</script>'.

El administrador navega a Components → Phoca Cart → Orders. El pedido inyectado aparece en la lista. XSS aún no se dispara en esta etapa.

Cuando el administrador hace clic en el pedido para abrir la vista de edición, el user_agent almacenado se renderiza sin escapar mediante itemText(). JavaScript se ejecuta inmediatamente.
URL de activación:
/administrator/index.php?option=com_phocacart&view=phocacartorder&layout=edit&id=<ORDER_ID>
