Rusty pearls: Postgres RCE on cloud databases
Coby Abrams (Cloud Security Researcher · Varonis), Tal Peleg (senior security researcher and cloud security team lead · Varonis)
BSides Las Vegas 2025 · Day 1
Overview
Tal (as introduced) and Kobe Abrams of Veronus (as transcribed) present a privilege-escalation style attack chain against PostgreSQL that starts from a surprising property of trusted PL/Perl: the ability to manipulate environment variables in ways the speakers argue should be confined to untrusted procedural languages. They chain that primitive through PL/Rust compilation mechanics—specifically how cargo invokes rustc—to achieve code execution in a database session context. The talk is explicit that the work began from a motivation to understand post-SQL injection impact on Amazon RDS where the provided admin is not a superuser. A secondary thread is responsible disclosure and cloud-provider collaboration: they briefly executed on AWS RDS, found the environment constrained, and triggered a rapid AWS response.

Key moments
- 2:00 PostgreSQL trust model: trusted vs untrusted languages—and the claim trusted PL/Perl can still mutate environment variables.
- 4:00 PL/Rust build chain: cargo calls rustc; denylist bypass via CARGOBUILDRUSTCWRAPPER vs removed RUSTCWRAPPER.
- 6:00 rust-gdb bash script pivot: using wrapper + gdb-related env to inject shell commands; live demo setup described.
- 8:00 Research origin: post–SQL injection impact on AWS RDS non-superuser admin; goal of shell access and cross-tenant testing.
- 10:00 Why PL/Rust: postmaster-mediated spawning breaks naive env tricks; searching extensions for direct binary execution paths.
- 12:00 AWS RDS attempt: constrained filesystem, rust-gdb path fails, bash env expansion workaround; rapid AWS IR response.
- 14:00 Defender guidance: patch minors since Postgres 12, least privilege, allowedextensions allowlist; call for managed-service research norms.
- 18:00 Q&A: Rust/Perl mitigations limit syscalls; discussion stays high level without a second exploit path.
Rusty pearls: Postgres RCE on cloud databases
Speakers: Tal (introduced as “T Pelleg” in the recording), Cloud Security Research Team Lead, Veronus (as transcribed); Kobe Abrams, Cloud Security Researcher, Veronus (as transcribed)
Conference: BSides Las Vegas
YouTube: https://www.youtube.com/watch?v=0c-KH_37Qds
Overview
Tal (as introduced) and Kobe Abrams of Veronus (as transcribed) present a privilege-escalation style attack chain against PostgreSQL that starts from a surprising property of trusted PL/Perl: the ability to manipulate environment variables in ways the speakers argue should be confined to untrusted procedural languages. They chain that primitive through PL/Rust compilation mechanics—specifically how cargo invokes rustc—to achieve code execution in a database session context. The talk is explicit that the work began from a motivation to understand post-SQL injection impact on Amazon RDS where the provided admin is not a superuser. A secondary thread is responsible disclosure and cloud-provider collaboration: they briefly executed on AWS RDS, found the environment constrained, and triggered a rapid AWS response.
Background
▶ Watch: PostgreSQL trust model: trusted vs untrusted languages—and the claim trusted ... (2:00)
PostgreSQL’s extension ecosystem includes language extensions that let developers implement functions in languages beyond SQL. The speakers summarize PostgreSQL’s model: untrusted languages can reach the underlying OS (environment, processes, filesystem) and therefore are superuser-only, while trusted languages are supposed to be constrained so ordinary roles cannot pivot to the host.
Perl is one such embedded language. The researchers focus on Perl’s %ENV hash (described in the talk as an “end of hashmap” / environment mechanism embedded in Perl) as a channel to read and write environment variables even under trusted PL/Perl, breaking the trust assumption in their testing.
Rust support in PostgreSQL (PL/Rust) introduces a compile step: creating a function triggers cargo, which in turn invokes rustc. Because child processes inherit environment, controlling environment variables can influence which binaries run during the build pipeline.
From a defender’s perspective, the important background detail is not “Rust is dangerous,” but that database engines increasingly embed build pipelines for developer ergonomics. Any time compilation happens on a server, you inherit the supply-chain surface area of the toolchain: wrappers, auxiliary scripts, helper binaries, and dynamic linker behavior. The speakers exploit that reality inside PostgreSQL rather than on a developer laptop, which changes who can trigger builds and under what credentials.
Key Findings
▶ Watch: rust-gdb bash script pivot: using wrapper + gdb-related env to inject shell c... (6:00)
- Trusted PL/Perl environment mutation: The speakers state they can set environment variables for the current PostgreSQL session using trusted PL/Perl, a capability they associate with untrusted languages only.
- Rust toolchain wrapper abuse: Rust’s hardening attempts to sanitize the environment before invoking
cargo, but the speakers describe a denylist approach. WhileRUSTC_WRAPPERis removed, another variable with equivalent effect—named in the talk asCARGO_BUILD_RUSTC_WRAPPER—is not removed, allowing redirection of the compiler invocation.
- Parameter injection via rust-gdb scripting: Controlling the wrapper alone did not grant arbitrary argument control initially. The chain continues by pointing the wrapper at
rust-gdb, a bash script shipped with Rust, combined with an environment variable (referenced asRUST_GDBor similar; the transcript spellsalso rust GDBin one place) to inject shell commands through script behavior.
- Exploit shape (high level): Create PL/Rust and PL/Perl extensions; define a PL/Perl function that sets
CARGO_BUILD_RUSTC_WRAPPERtorust-gdband adjusts the gdb-related variable to carry a payload; then create a trivial PL/Rust function to force compilation. The demo shows an error path but stdout evidence of execution (as described on stage).
- Why PL/Rust mattered for escalation: PostgreSQL’s extension API for spawning processes routes through postmaster, which the speakers say does not preserve the mutated environment in the child process—breaking naive “set env then
system()” chains. PL/Rust was identified as an extension path that runscargoin a way that does pick up the attacker-controlled environment (discovered via repository searching forexec/system/Commandpatterns).
- Cloud execution was limited: On AWS RDS, the environment was sparse (few binaries). The
rust-gdbpath failed because dependencies were missing. They pivoted to abashenvironment-variable expansion trick (details summarized verbally, not fully specified in the transcript) to run code briefly.
- AWS response: The speakers report very fast contact (emails, LinkedIn, CEO path), and AWS placing the instance into storage failed mode as a precaution. They characterize impact during the window as minimal for crossing tenants or stealing cloud credentials.
- Remediation guidance: Keep PostgreSQL updated (they state fixes exist from Postgres 12 onward in minor releases—verify against vendor advisories for exact versions), least privilege (don’t let untrusted roles create functions/extensions), and use
allowed_extensions(allowlist) to restrict extension loading.
Technical Deep Dive
▶ Watch: Why PL/Rust: postmaster-mediated spawning breaks naive env tricks; searching ... (10:00)
Trust model breakdown: The core issue is not “Perl is bad,” but that trusted PL/Perl still exposed environment variable control deep enough to become a sandbox escape primitive relative to PostgreSQL’s intended trust boundary.
Toolchain injection surface: Modern language toolchains are mini build systems with numerous environment knobs. Denylists are fragile: parallel variable names (RUSTC_WRAPPER vs CARGO_BUILD_RUSTC_WRAPPER) are classic parser differential problems across defensive checks.
Child process environment semantics: The speakers highlight PostgreSQL’s deliberate process-spawn architecture: extensions don’t freely fork with their own environment; postmaster mediates. That detail matters for exploit development because it forces you to find in-process or approved execution paths (here, compilation).
Cloud threat model: Managed PostgreSQL aims to cap privileges (RDS admin not superuser). The research asks what a database-compromise buys you: host access, metadata access, cross-tenant movement. Their on-RDS attempt suggests hardening and IR can compress attacker utility even when a primitive exists.
Comparative literature (as cited): The speakers reference Imre’s “Speckle Umbrella” story about code execution on GCP managed databases, and mention an Azure Cosmos DB for PostgreSQL issue not yet published at talk time. Treat publication status and details as unknown beyond their statement.
Why Perl was a research target (as stated): The speakers chose Perl because it ships from the official PostgreSQL sources and is widely present, increasing potential blast radius. They also note Perl’s long history and volume of legacy code, making behavioral changes harder—classic conditions where subtle trust-boundary mistakes hide.
Collaboration as a control for researchers: The talk’s recurring advice—“collaborate before running remote RCE”—is framed as reducing false-positive incident chaos and protecting researchers from being mistaken for adversaries. The distinctive database name anecdote is lightweight operational security: make human review faster and reduce time-to-understanding for provider SOCs.
Demo / Proof of Concept
▶ Watch: AWS RDS attempt: constrained filesystem, rust-gdb path fails, bash env expans... (12:00)
The live demo (as narrated) includes:
- Creating PL/Rust and PL/Perl extensions.
- Defining a PL/Perl function that sets
CARGO_BUILD_RUSTC_WRAPPERtorust-gdband configures the gdb-related environment to inject commands. - Creating a minimal PL/Rust function to trigger
cargocompilation. - Observing command effects via stdout despite error output from the compilation path.
The speakers joke about forgetting screenshots and recommend indicative database names; they named their test database Kobe, which they claim helped AWS identify the activity as research.
Defensive Implications
▶ Watch: Q&A: Rust/Perl mitigations limit syscalls; discussion stays high level withou... (18:00)
- Patch cadence: Treat PostgreSQL minor releases as security-bearing until proven otherwise; validate against your cloud provider’s supported versions matrix.
- Extension governance: Default-deny extension installation; allowlist only what you need; separate developer clusters from production if compilation features exist.
- Role modeling: If any role can create language functions or load extensions, you have collapsed much of the managed-service trust boundary.
- Detection: Build detection around anomalous extension installs,
CREATE FUNCTIONin uncommon languages, andcargo/rustcprocess execution on database hosts (provider-dependent visibility). - Research hygiene: Coordinate before executing RCE on shared cloud infrastructure; the speakers’ AWS anecdote is a case study in fast IR and constrained blast radius.
Managed-service note: Even when a database is “just PostgreSQL,” the surrounding image, packaging, extension availability, and syscall policies are vendor-defined. Defenders should treat extension catalogs and compilation toolchains as part of the attack surface, not as implementation details.
Verification discipline: The speakers encourage setting explicit research goals (what an adversary would want: network, credentials, cross-tenant movement) and measuring outcomes against those goals. Their RDS attempt is presented as a negative result that still advances understanding: “works in the lab” ≠ “works in production.”
Q&A note: A question is raised about embedding assembly inside a Rust extension to invoke syscalls directly. The speakers answer at a high level: Rust and Perl include mitigations intended to keep trusted languages from becoming arbitrary syscall machines; they indicate syscall-oriented tricks were not the path used in this work. Details of those mitigations are not expanded in the transcript beyond that reassurance.
Key Takeaways
- Trusted PL/Perl supplied an environment manipulation primitive that should have been untrusted-only per the speakers’ threat model.
- PL/Rust compilation turns env vars into code execution via
cargo/rustcwrapper semantics and arust-gdbscript pivot. - PostgreSQL’s postmaster spawning model complicates exploitation but does not eliminate it—extension-specific behaviors matter.
- Managed cloud PostgreSQL may still be vulnerable in principle, yet environment minimization and operator response can sharply limit real-world impact.
- Allowlisting extensions and patching are the operational lines of defense most teams can implement immediately.
- Collaborate early with cloud providers when researching remote execution on their managed services.
About the Speaker(s)
Tal introduces himself as cloud security research team lead at Veronus (as transcribed). Kobe Abrams is a cloud security researcher at Veronus with an interest in teaching cybersecurity. Additional biographical details beyond the transcript are unknown.
Reviews
Dr. Zero (Offensive Security Researcher) — STRONG ACCEPT
This is real vulnerability research with a clean narrative: break a trust boundary in PL/Perl, weaponize a modern toolchain’s env surface via PL/Rust, then sanity-check the cloud story with honest negative results. It is exactly the kind of work Postgres operators need to understand.
Heather Calloway (CISO) — STRONG ACCEPT
This talk translates cleanly into vendor risk and engineering policy: your database is not just a data store if it can compile code, load extensions, and inherit toolchain environment variables. The cloud portion is a lesson in blast-radius control and incident response maturity.