Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-54552

CVE-2026-54552: sh Python Library Privilege Escalation

CVE-2026-54552 is a privilege escalation flaw in the sh Python library that allows incomplete privilege drops when using the _uid option. Elevated processes retain privileged group access. This article covers technical details, affected versions, impact, and mitigation strategies.

Published:

CVE-2026-54552 Overview

CVE-2026-54552 is an incomplete privilege drop vulnerability [CWE-273] in the sh Python library, which provides subprocess replacement functionality for launching processes. Versions prior to 2.2.4 fail to fully drop supplementary group memberships when the _uid option is used from an elevated process. The child process changes its UID but retains the parent's supplementary groups. This allows the unprivileged child to access files or resources granted to privileged groups such as root, docker, disk, shadow, or sudo, violating the expected _uid privilege boundary.

Critical Impact

A process launched with _uid set to an unprivileged user retains supplementary group memberships inherited from the elevated parent, granting unintended access to files owned by privileged groups.

Affected Products

  • sh Python library versions prior to 2.2.4
  • Linux and Unix-like systems using sh for subprocess management
  • Applications relying on the _uid option in sh.py for privilege separation

Discovery Timeline

  • 2026-08-18 - CVE-2026-54552 published to NVD
  • 2026-08-18 - Last updated in NVD database

Technical Details for CVE-2026-54552

Vulnerability Analysis

The sh library provides a Python subprocess replacement with an _uid option that lets callers launch child processes as a different user. When the calling process runs with elevated privileges, developers expect _uid to enforce a complete privilege boundary. The pre-2.2.4 implementation invoked os.initgroups(target_name, target_gid) followed directly by os.setuid(target_uid), omitting the os.setgid(target_gid) call. As a result, the primary GID was not properly established and supplementary groups from the parent process could persist.

A child running under an unprivileged UID with lingering supplementary group memberships can read /etc/shadow via the shadow group, control containers via the docker group, or access raw block devices via the disk group. This produces a local privilege escalation path where the child performs actions inconsistent with its target user identity.

Root Cause

The root cause is an incomplete privilege-drop sequence in sh.py. Proper privilege dropping on Linux requires setting supplementary groups, the primary GID, and the UID in the correct order. The pre-patch code skipped setgid(), leaving the process with an inconsistent credential state.

Attack Vector

Exploitation requires local access and the presence of an application that runs sh from an elevated context and invokes child commands with _uid set to an unprivileged user. An attacker who controls the child command, or a user with access to files owned by inherited privileged groups, can leverage the retained group memberships to read sensitive files or interact with privileged services.

python
# Security patch in sh.py (source: github.com/amoffat/sh commit 3d855da)
                if ca["uid"] is not None:
                    os.initgroups(target_name, target_gid)
-
+                    os.setgid(target_gid)
                    os.setuid(target_uid)

                preexec_fn = ca["preexec_fn"]

Source: GitHub Commit Details. The patch inserts the missing os.setgid(target_gid) call between initgroups and setuid, ensuring the primary GID is set before the UID transition finalizes the credential change.

Detection Methods for CVE-2026-54552

Indicators of Compromise

  • Processes running under an unprivileged UID whose /proc/<pid>/statusGroups: line lists privileged GIDs such as those for root, docker, disk, shadow, or sudo.
  • Unexpected read access to /etc/shadow, Docker sockets, or raw disk devices by processes started via Python applications using sh.
  • Python applications importing sh at versions below 2.2.4 while running with elevated privileges.

Detection Strategies

  • Inventory Python environments for installed sh package versions using pip show sh or SBOM tooling, flagging any version below 2.2.4.
  • Audit /proc/<pid>/status on Linux hosts to identify mismatches between a process's effective UID and its supplementary group memberships.
  • Instrument audit rules on sensitive files such as /etc/shadow and /var/run/docker.sock to capture accessing PIDs and their credential state.

Monitoring Recommendations

  • Enable Linux auditd rules on group-owned sensitive resources and correlate access events with process credential snapshots.
  • Monitor package manager and dependency-scanning telemetry for continued use of vulnerable sh releases in production images and containers.
  • Track process ancestry for elevated services that spawn children with _uid, and alert on children that retain unexpected group memberships.

How to Mitigate CVE-2026-54552

Immediate Actions Required

  • Upgrade the sh package to version 2.2.4 or later in all Python environments, container images, and CI/CD pipelines.
  • Identify all services that run with elevated privileges and use sh with the _uid option, and validate their group membership behavior after upgrading.
  • Rotate credentials or secrets that may have been exposed to processes with unintended access to shadow, docker, or sudo group resources.

Patch Information

The fix is included in sh version 2.2.4. The patch adds the missing os.setgid(target_gid) call so the privilege-drop sequence establishes supplementary groups, primary GID, and UID in the correct order. See the GitHub Security Advisory, GitHub Pull Request Discussion, and GitHub Release Notes for details.

Workarounds

  • Avoid launching commands with the _uid option from elevated processes until the upgrade is applied.
  • Supply a custom preexec_fn that explicitly calls os.initgroups(), os.setgid(), and os.setuid() in the correct order to fully drop privileges.
  • Refactor privileged workflows to spawn helpers that already run as the target user, eliminating in-process privilege transitions.
bash
# Upgrade sh to the patched release
pip install --upgrade 'sh>=2.2.4'

# Verify installed version
python -c "import sh; print(sh.__version__)"

# Audit a running process for retained privileged groups
cat /proc/<pid>/status | grep -E '^(Uid|Gid|Groups):'

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.