CVE-2018-12028
Description
An Incorrect Access Control vulnerability in SpawningKit in Phusion Passenger 5.3.x before 5.3.2 allows a Passenger-managed malicious application, upon spawning a child process, to report an arbitrary different PID back to Passenger's process manager. If the malicious application then generates an error, it would cause Passenger's process manager to kill said reported arbitrary PID.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Phusion Passenger 5.3.x before 5.3.2 has an access control flaw allowing a malicious app to report a fake PID, leading to arbitrary process termination.
Vulnerability
An Incorrect Access Control vulnerability exists in the SpawningKit component of Phusion Passenger versions 5.3.x prior to 5.3.2 [1]. The bug allows a malicious application managed by Passenger, upon spawning a child process, to report an arbitrary, different PID back to Passenger's process manager [1]. This occurs because the code in SmartSpawner did not sufficiently validate the PID returned by the preloader process [2]. Phusion Passenger 5.3.2 addresses the issue by adding sanity checks, including a UID check and a check that the reported PID is a positive value [2].
Exploitation
An attacker must have the ability to deploy and run a malicious application managed by Phusion Passenger (i.e., the attacker must already have some level of access to the Passenger-managed application environment) [1]. No authentication is required beyond that. The attacker crafts the malicious application so that after spawning a child process, it reports an arbitrary PID (for example, the PID of a critical system process) back to the Passenger process manager [1]. Then the attacker causes the malicious application to generate an error, which triggers Passenger's process manager to send a kill signal to the reported arbitrary PID [1][2].
Impact
Successful exploitation allows an attacker to cause Passenger's process manager to terminate an arbitrary process on the system, specified by the attacker-chosen PID [1]. This is a denial-of-service (DoS) attack on the targeted process, which could be a critical system service, another application, or Passenger's own processes. The attacker achieves a high-availability impact by abusing the process manager's error-handling behavior, without needing direct write access to the target process [1].
Mitigation
The vulnerability is fixed in Phusion Passenger version 5.3.2 [1][2]. Users should upgrade to 5.3.2 or later immediately. The fix adds input validation and sanity checks on the PID returned by the preloader [2]. No workaround is documented for earlier versions. Phusion Passenger is not listed in CISA's Known Exploited Vulnerabilities (KEV) catalog as of the publication date.
AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
passengerRubyGems | >= 5.3.0, < 5.3.2 | 5.3.2 |
Affected products
1Patches
11e7c82deb490SpawningKit: do not allow killing the PID returned by the preloader until we have verified that it is genuine
1 file changed · +52 −7
src/agent/Core/SpawningKit/SmartSpawner.h+52 −7 modified@@ -840,16 +840,56 @@ class SmartSpawner: public Spawner { { TRACE_POINT(); pid_t spawnedPid = doc["pid"].asInt(); - ScopeGuard guard(boost::bind(nonInterruptableKillAndWaitpid, spawnedPid)); - UPDATE_TRACE_POINT(); - waitForStdChannelFifosToBeOpenedByPeer(stdChannelsAsyncOpenState, - session, spawnedPid); - - UPDATE_TRACE_POINT(); // How do we know the preloader actually forked a process // instead of reporting the PID of a random other existing process? - // For security reasons we perform a UID check. + // For security reasons we perform a bunch of sanity checks, + // including checking the PID's UID. + + if (spawnedPid < 1) { + UPDATE_TRACE_POINT(); + session.journey.setStepErrored(SPAWNING_KIT_PROCESS_RESPONSE_FROM_PRELOADER); + + SpawnException e(INTERNAL_ERROR, session.journey, session.config); + addPreloaderEnvDumps(e); + e.setSummary("The the preloader said it spawned a process with PID " + + toString(spawnedPid) + ", which is not allowed."); + e.setSubprocessPid(spawnedPid); + e.setStdoutAndErrData(getBackgroundIOCapturerData( + stdChannelsAsyncOpenState->stdoutAndErrCapturer)); + e.setProblemDescriptionHTML( + "<h2>Application process has unexpected PID</h2>" + "<p>The " PROGRAM_NAME " application server tried" + " to start the web application by communicating with a" + " helper process that we call a \"preloader\". However," + " the preloader reported that it started a process with" + " a PID of " + toString(spawnedPid) + ", which is not" + " allowed.</p>"); + if (!session.config->genericApp && session.config->startsUsingWrapper + && session.config->wrapperSuppliedByThirdParty) + { + e.setSolutionDescriptionHTML( + "<h2>Please report this bug</h2>" + "<p class=\"sole-solution\">" + "This is probably a bug in the preloader process. The preloader " + "wrapper program is not written by the " PROGRAM_NAME " authors, " + "but by a third party. Please report this bug to the author of " + "the preloader wrapper program." + "</p>"); + } else { + e.setSolutionDescriptionHTML( + "<h2>Please report this bug</h2>" + "<p class=\"sole-solution\">" + "This is probably a bug in the preloader process. The preloader " + "is an internal tool part of " PROGRAM_NAME ". Please " + "<a href=\"" SUPPORT_URL "\">" + "report this bug</a>." + "</p>"); + } + throw e.finalize(); + } + + UPDATE_TRACE_POINT(); uid_t spawnedUid = getProcessUid(session, spawnedPid, stdChannelsAsyncOpenState->stdoutAndErrCapturer); if (spawnedUid != session.uid) { @@ -897,6 +937,11 @@ class SmartSpawner: public Spawner { throw e.finalize(); } + UPDATE_TRACE_POINT(); + ScopeGuard guard(boost::bind(nonInterruptableKillAndWaitpid, spawnedPid)); + waitForStdChannelFifosToBeOpenedByPeer(stdChannelsAsyncOpenState, + session, spawnedPid); + UPDATE_TRACE_POINT(); string alreadyReadStdoutAndErrData; if (stdChannelsAsyncOpenState->stdoutAndErrCapturer != NULL) {
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-jjhj-8gx7-x836ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2018-12028ghsaADVISORY
- security.gentoo.org/glsa/201807-02ghsavendor-advisoryx_refsource_GENTOOWEB
- blog.phusion.nl/passenger-5-3-2ghsax_refsource_MISCWEB
- github.com/phusion/passenger/commit/1e7c82deb4901c438f583737d8c9f2aac264737cghsaWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/passenger/CVE-2018-12028.ymlghsaWEB
News mentions
0No linked articles in our index yet.