A Busy Week in Security: What It Means for WorkOS and for You
Node.js and PHP shipped RCE fixes, a malicious LiteLLM release hit PyPI, and eMudhra CA keys were compromised. What WorkOS did, and some recommendations for your stack.
In the space of a few days, several serious security issues hit widely used software:
- remote code execution vulnerabilities in Node.js and PHP
- a malicious LiteLLM release published through the project's own pipeline
- the compromise of private keys belonging to eMudhra intermediate certificate authorities
While the fixes were different, the lesson is the same: your security depends on the runtimes, packages and trust relationships underneath your application, not just on the code you write.
Our Security and Engineering teams spent the week assessing exposure, deploying patches and mitigations, checking what is actually running in production, and following up on fixes that depend on vendors. This post explains what we did and what you may want to check in your own infrastructure.
At a Glance
Node.js: CVE-2026-111497 and Related Fixes
Did WorkOS Patch?
Yes. WorkOS services run on Node.js, and we've patched Node.js across our fleet. We finished rolling the patched runtime out to production at about 02:15 UTC on October 22 and confirmed that the patched versions are running.
What Happened
On October 21, Node.js released security updates for several vulnerabilities across the 22.x, 24.x and 26.x release lines. The most serious, CVE-2026-111497, is an out-of-bounds write in Node's bundled Brotli decoder that can allow remote code execution.
Brotli is a compression format that Node can decompress natively. The most direct exposure is outbound: Node's built-in fetch() automatically decompresses Brotli-encoded responses, so a malicious or compromised server that your code calls could send a crafted response. Code that decompresses request bodies, uploads, or other user-supplied data is exposed too. The same release also fixes several high-severity TLS hostname-verification bypasses and updates Node's bundled CA certificates in response to the eMudhra compromise.
How Can You Protect Yourself?
- Find every place Node.js runs. Include deployed applications, background workers, container images, build systems and CI. Upgrading a WorkOS SDK or any other npm package doesn't change the Node.js runtime.
- Upgrade to a fixed release: Node.js 22.23.4, 24.22.1 or 26.12.1, or a newer supported release.
- Rebuild and redeploy. Rebuild container images, redeploy them, and restart long-running processes.
- Verify the running version. Check
process.versionin the running workload, not just the version in your Dockerfile or.nvmrc - Check managed platforms. If a hosting or serverless provider manages your runtime, follow their guidance on whether you need to redeploy or change a runtime setting.
PHP: CVE-2026-109618 and CVE-2026-109619
Did WorkOS Patch?
No. WorkOS services don't use PHP, so these vulnerabilities don't affect them. We publish PHP SDKs, but they run on your own PHP installation and don't need an update. Your PHP runtime likely does.
What Happened
The PHP project disclosed two critical vulnerabilities that can allow unauthenticated remote code execution. Their scope is unusually broad. The PHP team considers every PHP installation that serves web requests to be at risk, whether it runs under php-fpm, Apache with mod_php, php-cgi or any other server setup. Fixes cover every supported release line, and the team also published source patches for PHP 7.4, 8.0 and 8.1, so assume that whatever version you run is affected. Risk is highest with mod_php, where the PHP team demonstrated an exploit that a single unauthenticated request can trigger before any application code runs. Your application doesn't need a bug of its own to be exploitable.
Both bugs are in PHP's request lifecycle rather than in any particular extension. CVE-2026-109618 occurs when PHP runs out of memory while setting up a request: cleanup later treats the partly initialized data as valid. CVE-2026-109619 lets state from one request survive after its memory is freed, so a later request handled by the same worker can use it.
PHP has since published a follow-up advisory about a related issue in session upload progress, CVE-2026-115560. It only affects applications that change PHP's session serialization handler at runtime while session upload progress is enabled, and PHP considers that setup unlikely. PHP will fix it in its next regular bugfix release.
How Can You Protect Yourself?
- Upgrade PHP. The PHP security announcement lists the fixes in PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12. If you install PHP from a Linux distribution or a hosting provider, use their updated package, which may include the fix without changing PHP's version number.
- Move off PHP 8.1 and older. These versions no longer get official releases, so plan a move to a supported version.
- Restart every worker. Long-lived PHP-FPM, Apache and FrankenPHP workers keep running the old code until they restart onto the new version.
- Turn off session upload progress for now. As a precaution, PHP recommends setting
session.upload_progress.enabled=0until its next bugfix release. Set it inphp.inior your server or pool configuration, then restart your workers. If you already applied this setting as a mitigation for CVE-2026-109619, keep it in place. - Verify the version your web server uses. The
phpcommand-line binary can be a different installation from the one serving requests, so check the version reported by your web server or FPM pool. - Check where your PHP packages come from. Third-party package repositories and community builds of PHP don't always publish security fixes at the same time as the PHP project. If yours hasn't released a fixed build, switch to your distribution's packages or build PHP from source.
- Use mitigations only as a stopgap. If you can't update immediately, PHP has published temporary mitigations. They reduce exposure rather than remove it, so they don't replace the update.
LiteLLM: Malicious 1.107.0 Release
Did WorkOS Patch?
No. WorkOS doesn't use LiteLLM, and our review found no exposure to the compromised release.
Even if we had used LiteLLM, one of our standing practices would very likely have kept this release out. We wait seven days by default before installing newly published package versions. We carefully make exceptions when we need an urgent security fix, but the delay gives the wider community time to spot and pull a compromised release before it reaches us. The malicious LiteLLM release was live on PyPI for less than two hours.
What Happened
LiteLLM reports that malicious 1.107.0 artifacts were published to PyPI, Docker Hub and GHCR on October 21. For part of that time, floating Docker tags such as latest also pointed to the compromised image. The malware steals credentials and loads remote-access tools.
This isn't an ordinary vulnerability, and an ordinary upgrade won't fix it. LiteLLM is often deployed as a gateway that holds API keys for many model providers, so a compromised instance can expose a lot of credentials.
How Can You Protect Yourself?
- Check whether you ran it. Check installed packages and deployed images, including developer machines and CI environments, against the vendor's list of affected artifacts and time windows. Your dependency file may not show what was actually installed, especially if you use unpinned versions or floating tags.
- If it ran, treat the environment as compromised. Don't try to clean it in place. The malicious package drops a
.pthfile and asitecustomize.pyinto site-packages, and Python runs both automatically every time it starts, so even runningpipto uninstall the package runs the malware again. Rebuild from clean, verified artifacts instead. - Rotate credentials from a clean system. Rotate every credential the environment could reach. LiteLLM's guidance includes the instance or task IAM role, every provider key stored in the proxy database, LiteLLM's master and virtual keys, the database password and any secret in the environment of a process on the host. Changing the package version doesn't undo credential theft that may already have happened.
- Investigate access. Review cloud audit logs for unexpected use of those credentials, especially from outside your infrastructure.
- Pin dependencies by hash. A lockfile with hashes (for example,
pip install --require-hashesor a uv or Poetry lockfile) and container images referenced by digest (image@sha256:…) rather than by tag stop a new release, or a repointed tag, from entering a build without a deliberate change. - Add a short cooldown for new package versions. Holding newly published versions for a few days, as we do, gives the community time to catch a compromised release before it reaches you. Dependency update tools can enforce this for you: Renovate's
minimumReleaseAgesetting and Dependabot'scooldownoption both hold off on update pull requests until a release has been public for a set number of days. A cooldown in these tools only governs the updates they propose, so pair it with hash pinning to keep unpinned installs from pulling in a brand-new release.
eMudhra: Compromised Intermediate CA Keys
Did WorkOS Patch?
Our outbound connections could have trusted forged certificates, so we treated this as urgent. We finished deploying a mitigation for SSO flows to production at about 23:30 UTC on October 20, and all WorkOS services now distrust the compromised eMudhra intermediate certificates. We're also adopting updated certificate bundles as vendors release them.
We take this kind of issue especially seriously because SSO depends on TLS. During SSO flows, WorkOS fetches identity provider metadata and signing keys and exchanges authorization codes for tokens, all over TLS. The certificate check is how we know that this information comes from the real identity provider. If a forged certificate were trusted, an attacker in the right network position could substitute their own signing keys and get forged sign-ins accepted.
What Happened
On October 17, a researcher reported that the private keys for eight intermediate certificate authorities operated by eMudhra, a publicly trusted CA, had been generated incorrectly. The keys could be recovered from the public certificates themselves. That meant anyone could use the keys to issue trusted certificates for domains they don't control. Certificates for well-known domains issued by these CAs have since appeared in public Certificate Transparency logs.
Major browsers blocked the affected intermediates within days. The longer tail is everything else: servers, scripts and services that make TLS connections without a browser's protections.
Exploiting this still requires an attacker to intercept traffic, for example through a compromised network, a DNS or routing hijack, or a malicious proxy. That's a high bar. But the consequences are severe and hard to detect: a client that trusts a forged certificate has no reason to suspect that it isn't talking to the real service. The risk also isn't limited to sites that use eMudhra certificates. A forged certificate can impersonate any domain, including a service you depend on, to any client that still trusts the affected CAs.
How Can You Protect Yourself?
- Identify flows that rely on the public chain of trust. Ask which of your systems rely on TLS to decide who they're talking to. Common examples include fetching signing keys (JWKS), OAuth token exchanges, payment and other third-party APIs, and service-to-service calls over the public internet.
- Find every trust store your code uses. Many applications, languages and runtimes bring their own trust store instead of using the operating system's, so an OS update alone may not be enough. For example:
- Node.js compiles a copy of Mozilla's CA list into its binary.
- Python's
requestslibrary trusts thecertifipackage. - Java ships its own
cacertsfile with each JDK. - Container images copy in the operating system's CA bundle when they're built and keep that copy until they're rebuilt.
- Chrome and Firefox maintain their own root stores, although both have already blocked the affected intermediates.
- Update each one. Apply operating system updates, upgrade Node.js, update
certifiand your JDK, and rebuild container images. - Confirm the update explicitly distrusts the affected certificates. Most HTTP clients and TLS libraries don't check revocation or enforce Certificate Transparency the way browsers do, so eMudhra's revocation of the intermediates doesn't protect them. The same keys were also cross-certified by Sectigo under a root that many trust stores include, so removing eMudhra's roots alone doesn't close every path. Check that your vendor's update accounts for the cross-certificates.
- Don't weaken TLS as a workaround. Don't disable certificate verification, and don't remove unrelated CAs in bulk.
Why This Matters for Authentication
Weeks like this show why security needs constant attention. Authentication sits in front of everything our customers build, and it depends on exactly the layers tested this week: the runtimes that handle untrusted input, the packages we install, and the certificates that tell us who we're talking to. That's why WorkOS spends so much time getting the details right: working out where an issue really applies, fixing it and confirming that the fix is live. And it's why we share what we learn, so you can make good decisions about the systems you run.