
CVE-2026-11837: локальное повышение привилегий в модуле authorized_key из ansible.posix через chown со следованием по символьным ссылкам. Технический разбор; родственный CVE-2024-9902.
authorized_keyЛокальное повышение привилегий в Ansible-модуле ansible.posix.authorized_key через chown, следующий по символьным ссылкам (и создание файла, следующее по символьным ссылкам), в каталоге ~/.ssh пользователя и файле authorized_keys.
Это описание уязвимости, о которой я сообщил и которой был присвоен идентификатор CVE-2026-11837 компанией Red Hat Product Security (CNA). Она публикуется здесь как техническая запись, а не как заявление о новизне: проблема является родственной CVE-2024-9902 в модуле, который не был охвачен более ранним исправлением.
Опубликованное подтверждение Red Hat: «Red Hat хотела бы поблагодарить Valentino Paulon за сообщение об этой проблеме».
Когда плейбук, выполняющийся от имени root, использует ansible.posix.authorized_key для управления ключами локального пользователя, вспомогательная функция keyfile() модуля:
~/.ssh пользователя и файла ~/.ssh/authorized_keys с помощью обычного os.chown (не os.lchown), иopen(..., "w") (без O_NOFOLLOW).При значении по умолчанию follow=False модуль не следует за символьными ссылками с заменой целевого объекта и не отвергает их; он работает напрямую с путём, поэтому ядро следует по любой символьной ссылке, которую непривилегированный целевой пользователь заранее разместил в своём собственном ~/.ssh. Это даёт два примитива, которые передают владение путём, контролируемым root, непривилегированному пользователю, который затем повышает привилегии до root. Оба примитива были полностью воспроизведены на коллекции в состоянии HEAD.
keyfile() (plugins/modules/authorized_key.py), с параметрами по умолчанию manage_dir=True, follow=False:
if manage_dir:
if not os.path.exists(sshdir): # os.path.exists FOLLOWS symlinks
try:
os.mkdir(sshdir, int('0700', 8))
...
os.chown(sshdir, uid, gid) # UNCONDITIONAL, plain chown, follows symlink
os.chmod(sshdir, int('0700', 8)) # follows symlink
if not os.path.exists(keysfile): # follows symlink
...
f = open(keysfile, "w") # plain open(), no O_NOFOLLOW, follows symlink
...
try:
os.chown(keysfile, uid, gid) # UNCONDITIONAL, plain chown, follows symlink
os.chmod(keysfile, int('0600', 8)) # follows symlink
except OSError:
pass
sshdir и keysfile берутся из домашнего каталога целевого пользователя из passwd (pwd.getpwnam(user).pw_dir) — каталога, которым непривилегированный целевой пользователь владеет и управляет. Параметр follow (по умолчанию False) только определяет, вызывать ли os.path.realpath() для пути; ни в одном из случаев не выполняется проверка os.path.islink, открытие с O_NOFOLLOW, os.lchown или удаление и замена уже существующей символьной ссылки. Понижение привилегий (seteuid/setfsuid) не выполняется; всё работает от имени root.
Два вызова os.chown выполняются безусловно, вне проверок if not os.path.exists(...), поэтому они срабатывают независимо от того, существовали ли каталог/файл ранее. Именно это делает оба примитива надёжными.
Оба подтверждены полностью на временной Linux-VM, с ansible.posix на HEAD. victim — непривилегированный локальный пользователь (uid 1000). Модуль запускается от имени root, точно так же, как это делал бы плейбук оператора. Канарейки выступают в роли чувствительных root-целей.
Вектор 1: символьная ссылка на каталог (chown существующего root-каталога)
victim: ln -s /root/AD_CANARY ~/.ssh (где /root/AD_CANARY — существующий каталог, принадлежащий root).authorized_key для victim./root/AD_CANARY изменился с root:root на victim:victim. Вызов os.chown(sshdir, ...) последовал по символьной ссылке ~/.ssh и передал root-каталог непривилегированному пользователю.Вектор 2: висячая символьная ссылка на файл (создание + chown нового файла по root-пути)
victim (при обычном каталоге ~/.ssh): ln -s /root/AF_CANARY ~/.ssh/authorized_keys (цель не существует).authorized_key для victim./root/AF_CANARY был создан, владелец — victim:victim, режим 0600. open(keysfile, "w") создал цель через символьную ссылку, а os.chown(keysfile, ...) передал её пользователю.В обоих случаях непривилегированный пользователь в итоге становится владельцем пути, контролируемого root. Указав ссылку на каталог внутри /etc (вектор 1) или на новый файл внутри /etc/cron.d/ или /etc/sudoers.d/ (вектор 2), можно получить root стандартным последующим шагом: пользователь, став владельцем, перезаписывает цель.
Это родственная проблема CVE-2024-9902 (generate_ssh_key модуля user в ansible-core), которая устраняла тот же класс проблем со следованием по символьным ссылкам. authorized_key находится в отдельной коллекции ansible.posix и не был изменён этим исправлением; паттерн chown/создания, следующий по символьным ссылкам, по-прежнему присутствовал и не был защищён. Она заявлена как тот же принятый класс в модуле, которого не достигло предыдущее исправление, а не как новая первопричина.
ansible.posix.authorized_key, нацеленной на учётную запись жертвы (обычное использование этого модуля). Локальный пользователь заранее размещает символьную ссылку в своём собственном ~/.ssh; он не запускает плейбук. Это действие инициируется оператором: та же модель срабатывания, что и у CVE-2024-9902, которую Red Hat приняла с мерой смягчения «не запускать против недоверенных учётных записей». Предусловие указано явно, а не квалифицировано как самосрабатывающее.os.open(keysfile, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600) и работайте с дескриптором; отказывайте (или удаляйте и заменяйте, согласно контракту docstring для follow=False), если sshdir или keysfile являются символьной ссылкой.os.chown(...) на os.lchown или на os.fchown для безопасно открытого дескриптора, а также используйте os.fchmod вместо os.chmod, чтобы владелец и права доступа не могли быть перенаправлены через ссылку.chown/chmod, чтобы они применялись только к пути, который сам модуль только что безопасно создал, а не к уже существующему (возможно, являющемуся символьной ссылкой) пути.| Дата | Событие |
|---|---|
| 2026-06-08 | Сообщено на [email protected] (Red Hat Product Security в копии как CNA), описано как родственная проблема CVE-2024-9902 |
| 2026-06-10 | Присвоен и опубликован CVE-2026-11837; авторство принято |
MIT. См. LICENSE.
| CVE | CVE-2026-11837 |
| Компонент | коллекция ansible.posix, файл plugins/modules/authorized_key.py, функция keyfile() |
| Тип | Повышение привилегий (локальное). CWE-59 / CWE-61 (следование по символьным ссылкам) с CWE-282 (некорректное управление владельцем) |
| CVSS | 7.3 (высокий) |
| Опубликовано | 2026-06-10 |
| Сообщил | Valentino Paulon |