Третьего июня 2026 года стало известно о серьёзной уязвимости в популярном PHP-фреймворке Laravel. Проблема затрагивает компонент Passport, который отвечает за реализацию протокола OAuth2 для аутентификации через сторонние приложения. Ошибка, получившая идентификатор CVE-2026-39976, позволяет злоумышленнику выдать себя за любого пользователя системы, используя специальный тип токена - client_credentials (учётные данные клиента, предназначенные для межсерверного взаимодействия без участия человека). Эта брешь имеет высокий уровень опасности по шкале CVSS (7,1 балла) и угрожает сайтам, использующим версии Passport с 13.0.0 по 13.7.1 включительно. Разработчики уже выпустили исправление в версии 13.7.1.
В чём суть проблемы
Чтобы понять уязвимость, нужно разобраться, как работают токены OAuth2. В стандартной схеме пользователь входит в приложение, после чего сервер выдаёт ему токен доступа. Этот токен содержит полезную нагрузку (payload) в формате JWT (JSON Web Token) - компактного и защищённого способа передачи данных между сторонами. В поле subject (обычно обозначается как sub) записывается идентификатор пользователя, чтобы сервер мог определить, кто именно обращается к ресурсам.
Однако существует специальный тип токена - client_credentials. Он предназначен для автоматических сценариев, когда одна программа общается с другой без участия человека. В этом случае, поскольку аутентифицированного пользователя нет, библиотека league/oauth2-server (основной компонент OAuth2 для PHP) устанавливает в поле sub идентификатор клиента (то есть самого приложения), а не пользователя.
Тем не менее разработчики Laravel Passport реализовали обработку токенов через класс TokenGuard. Этот класс после проверки JWT передаёт значение из поля sub в метод retrieveById(), который предназначен для поиска пользователя по его идентификатору. Проблема в том, что перед этим вызовом не производится проверка, является ли переданный идентификатор действительно идентификатором пользователя. В результате токен, созданный для программы, может случайно "подобрать" реального пользователя, чей ID совпадает с идентификатором клиента.
Когда атака возможна
На первый взгляд риск кажется невысоким. По умолчанию Laravel Passport использует UUID (универсальные уникальные идентификаторы) для клиентов. Это длинные строки вида "550e8400-e29b-41d4-a716-446655440000", которые никогда не совпадут с целыми числами, используемыми для идентификации пользователей. Однако есть одно важное исключение.
Если разработчик по какой-то причине отключил использование UUID для клиентов, установив параметр Passport::$clientUuids в значение false, то клиенты получают целочисленные идентификаторы, начиная с единицы. В такой конфигурации, если в базе данных существует пользователь с ID, равным 1, а также клиент с ID, равным 1, то токен, выданный для этого клиента, при проверке через TokenGuard будет идентифицирован как токен пользователя. Иными словами, программа, которая должна была работать только от своего имени, получает доступ к данным и действиям конкретного человека.
В документации к Laravel Passport действительно упоминается, что при использовании middleware EnsureClientIsResourceOwner (промежуточного слоя, проверяющего, что клиент является владельцем ресурса) в сочетании с отключёнными UUID существует риск разрешения неверного пользователя. Тем не менее описание этого риска, судя по всему, не останавливало разработчиков от использования подобной конфигурации.
Последствия и масштаб
Уязвимость имеет невысокий порог входа: для её использования требуется лишь учётная запись с низким уровнем привилегий (Privileges Required: Low) и никакого взаимодействия с жертвой (User Interaction: None). Атака может быть проведена удалённо через сеть (Attack Vector: Network). При этом сложность атаки оценена как высокая (Attack Complexity: High), что предполагает необходимость определённых условий, а именно - совпадения идентификаторов и возможности отправить вредоносный запрос.
Тем не менее последствия потенциально разрушительны. Злоумышленник, сумевший воспользоваться этой брешью, получает доступ к конфиденциальной информации любого пользователя, чей ID совпал с ID клиента. Это могут быть личные данные, история заказов, банковские реквизиты, переписка. Оценка конфиденциальности по CVSS - высокая (High). Кроме того, атакующий может выполнять действия от имени этого пользователя, например, изменять настройки, оставлять комментарии или совершать покупки. Правда, возможность изменения данных оценивается как низкая (Low), поскольку атака даёт доступ к аутентификации, но не обязательно к операциям записи. Важно отметить, что уязвимость затрагивает только конфиденциальность и целостность данных, но не влияет на доступность системы.
Что делать
Разработчики Laravel Passport выпустили исправление в версии 13.7.1. Всем пользователям, использующим затронутые версии (от 13.0.0 до 13.7.1), настоятельно рекомендуется немедленно обновить пакет. Обновление устраняет проблему путём добавления проверки, гарантирующей, что токен клиента не может быть ошибочно принят за токен пользователя.
Если по каким-то причинам обновление невозможно, существует временная мера - полностью отключить использование токенов типа client_credentials в своём приложении. В этом случае злоумышленник не сможет воспользоваться уязвимостью, так как атакующие токены просто не будут создаваться. Однако такой подход может нарушить работу легитимных сервисов, использующих межмашинную аутентификацию.
На данный момент информации о реальных атаках, использующих эту уязвимость, в открытых источниках нет. Тем не менее учитывая популярность Laravel (один из самых распространённых PHP-фреймворков в мире), а также высокий потенциал ущерба, промедление с обновлением крайне нежелательно. Специалистам по информационной безопасности и разработчикам следует проверить конфигурацию своих проектов на использование целочисленных идентификаторов клиентов и, в случае обнаружения такой настройки, в кратчайшие сроки установить патч.
Ссылки
- https://www.cve.org/CVERecord?id=CVE-2026-39976
- https://github.com/laravel/passport/security/advisories/GHSA-349c-2h2f-mxf6