PHP CVE-2026-109618 and CVE-2026-109619 (PHP2Shell): The Out-of-Memory Escape Hatch Corrupts the Interpreter
When a PHP request exceeds its memory_limit, the interpreter does not clean up in an orderly way. It jumps out of the C function that is currently running via longjmp(), no matter how far that function had got with its work. For decades this jump was treated as a convenient escape hatch. CVE-2026-109618 and CVE-2026-109619 show what it leaves behind: half-initialised structures that the subsequent cleanup trusts as valid, and global state that stays in the worker and points into the memory of a request that ended long ago. Under Apache with mod_php a crafted multipart request is enough, before your own code has run a single line. The fix in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 therefore removes the jump on memory exhaustion altogether. The way the release itself went off the rails also shows how little control you have over the timing of a patch.
TL;DR — 90 seconds
- What: Two memory-safety bugs in the PHP core. With
CVE-2026-109618, aborting on memory exhaustion leaves half-initialised request data behind. WithCVE-2026-109619, global state survives the end of a request and is used by the next request in the same worker. - Severity: Both flaws are rated CVSS 4.0 9.2 (
AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N). They are not in the CISA KEV catalog, but several security vendors report exploitation attempts. - Who is affected: Every PHP installation that serves web requests, which means mod_php, PHP-FPM, FrankenPHP and LSAPI. The attack is easiest against mod_php, where it needs no application code at all.
- What to do: Update to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35, restart all workers and rebuild your container images. FrankenPHP ships the fixes from 1.13.2 onwards.
- What would have helped beforehand: Limits on request size and multipart structure in front of PHP, upload progress switched off, and a worker that finds neither a shell nor internet access after a takeover. Only the patch removes the actual cause.
From escape hatch to memory corruption
PHP manages the memory of a request itself. Every allocation through emalloc() goes through the Zend Memory Manager, which keeps count and raises the familiar fatal error “Allowed memory size of … bytes exhausted” once memory_limit is exceeded. The engine then calls zend_bailout(), which performs a longjmp() back to the last recovery point the engine marked earlier with setjmp(). According to the C standard, such a jump only restores the stack of that recovery point. Whatever the skipped functions still intended to do, from initialising a field to freeing a buffer, simply never happens.
As long as this happens in the middle of running a script, it usually works out, because PHP discards the entire request memory at the end anyway. It becomes dangerous wherever structures are reachable before they are fully built. That is exactly what advisory GHSA-w8hw-w9fx-j79w describes: in certain situations request memory is already linked in before it has been completely initialised. If an allocation fails at that moment, the memory is left in an invalid state, and request shutdown later reads that state as if it were correct, or even branches on it. According to the advisory this produces a use-after-free situation that can be pushed all the way to code execution.
Why an attacker can choose the moment of memory exhaustion becomes clear in the multipart parser, which splits up form data and uploads before your script starts. The advisory names three levers. Multipart requests without a usable Content-Length get past the initial post_max_size check. A single part may carry any number of headers, whose internal representation takes up a multiple of their raw size. And empty file fields do not count against max_file_uploads but still create metadata arrays, whose cost multiplies with nested field names. Combining these levers lets an attacker steer memory usage so precisely that the limit breaks at a chosen point. The CVSS vector rates this as high attack complexity because timing and heap layout have to line up. I read that as effort, not as a hurdle that stops a determined attacker.
The second flaw starts where a worker process serves several requests in a row. PHP keeps global state for errors, sessions, objects and extensions, which it resets between two requests. According to advisory GHSA-6wmf-4rv5-p3rp, a fatal error in the wrong place can prevent that reset, triggered for instance by memory exhaustion, a timeout, a failed require or a parse error. An attack then needs a producer that stores request-scoped data globally and a consumer that reads it in the next request before regular initialisation. The advisory names two such consumers: warnings PHP raises while applying certain INI settings before initialisation, and session upload progress, which accesses session state before the session itself is started. The strongest case on PHP 8.5 uses fatal_error_backtraces as the producer, because error output stores backtrace data whose reset was missing from shutdown. The confirmed exploit against mod_php builds on it, and via upload progress the advisory also validated code execution against mod_php and PHP-FPM.
Both bugs share a root that I consider the real lesson. The code assumed that nothing depending on clean state would happen after a fatal error, because the request ends anyway. The process does not end, though. It still cleans up, and afterwards it serves the next request.
Changes in the fix commit
Fix commit 3584a98 is titled “Avoid state corruption via bailout” and is unusually large for a security fix: it touches around 390 files, from the Zend core through main/rfc1867.c and the SAPI code to extensions such as json, pcre, session, mbstring and opcache. According to the commit message it does two things. It replaces the bailout on memory exhaustion with an orderly unwind via UnwindExit, and it explicitly resets the global variables that can be read when a request starts.
Alexandre Daubois from the PHP security team describes the new logic like this: memory_limit becomes a soft limit. When a request exceeds it, PHP records a pending error, the running C function finishes its work normally, and only at the next VM check point, such as a jump or a function call, does PHP start the unwind. The multipart parser cleans up and stops, after which the SAPI reports the fatal error as usual. To stop an attacker from stretching the soft limit indefinitely, there is also a hard limit, the new setting memory_hard_limit_percent. According to Daubois it defaults to twice memory_limit for limits below 1G, so 256M with the default of 128M. Crossing that line ends the process immediately with _exit(137).
The size of the commit shows how deep the old assumption ran. Until now every C function that requested memory could rely on a failed allocation never returning to it. After the fix it does return, and every one of these functions has to cope with that. On top of that come many new tests that deliberately cause memory exhaustion at specific points. So the bug was not a single forgotten check but an assumption the interpreter relied on in countless places.
From a crafted form to a shell in the worker
The prerequisites are modest, and that is what makes these flaws so serious. PHP ships with a finite memory_limit, and only then is there a memory exhaustion an attacker can provoke. Session upload progress is enabled by default according to the PHP documentation, and fatal_error_backtraces is also set to 1 out of the box in PHP 8.5. A default installation is therefore affected in both cases without anyone having misconfigured anything.
Conceptually, an attack on CVE-2026-109618 works like this: the attacker sends a multipart request whose structure drives memory usage to just below the limit and then lets the allocation fail at a point where a structure is half finished. The cleanup carries on with that state, and with targeted heap grooming this can be turned into code execution with the privileges of the web worker. Under mod_php, shutdown runs even after a failed startup according to the advisory, so the attack needs no application code there at all. Under PHP-FPM the child process exits after a failed startup. The PHP Foundation has nevertheless confirmed code execution on FPM via application-side code paths, but there is no application-independent demonstration for it. According to the advisory FrankenPHP calls shutdown unconditionally and is therefore considered likely vulnerable.
What a successful takeover costs depends on what the worker can see. In a typical TYPO3 or Symfony installation that means the database credentials, the encryption key, API tokens from the configuration and write access to the web root. From there it is a short way to a web shell, manipulated pages and access to everything the network behind the web server can reach.
That puts every PHP process that handles requests from the network at risk. Pure CLI processes such as cron jobs or queue workers that do not parse multipart data from outside are barely exposed, although I derive that from the described attack path rather than from the advisory. Plenty of wrong version information circulated. The advisories only list branches 8.2 to 8.5 as affected and patched. According to Daubois the mechanism goes back to the PHP 5.3 allocator, but an exploit for such old versions is not documented.
| CVE | Affected | Fix | Precondition | CVSS |
|---|---|---|---|---|
| CVE-2026-109618 (GHSA-w8hw-w9fx-j79w) | PHP 8.2 before 8.2.35, 8.3 before 8.3.36, 8.4 before 8.4.27, 8.5 before 8.5.12 | 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 | Finite memory_limit, web SAPI; under mod_php without application code | 9.2 (critical) |
| CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp) | as above | as above | Worker serves multiple requests; producer such as fatal_error_backtraces, consumer such as upload progress | 9.2 (critical) |
The exploitation picture is murky. Up to the release the security team says it found no working public proof of concept, but it writes that an accidentally published video sped up the development of various exploits. Cloudflare reported early attack attempts and temporarily deployed WAF rules, Patchstack and Aikido report exploitation according to SOCRadar, without publishing details, and Chainguard CEO Dan Lorenc told The Register that his company’s honeypots caught attacks on the flaws from Chinese and Russian IP addresses on October 21. None of the sources documents a successful compromise. As of October 21 the flaws are not in the CISA KEV catalog, and FIRST’s EPSS API still returned no score for either CVE on October 22. The authorities reacted early anyway. CISA called for immediate patching, CERT-EU advised on October 20 to prepare for it, and the UK NCSC issued a warning ahead of the release.
Leak, video and a broken embargo
The backstory goes further back than this week’s excitement suggests. According to the PHP Foundation, a core developer came across the first signs of the OOM problem as early as 2024 during an audit by Quarkslab, organised through OSTIF and funded by the Sovereign Tech Agency. At the time exploitation seemed theoretical, and work on a fix stalled and restarted repeatedly over months. The Foundation itself calls this a structural failure. Things became serious on August 11, 2026, when Calif reported an RCE with the same root cause as part of an audit and OpenAI independently found the same cause on the same day. Wiz and OpenAI added further attack paths in August and September.
On October 20 at around 15:00 UTC the two CVE numbers appeared in a since-deleted Hacker News post and on social media, with the wrong date and a wrong CVSS score of 10.0. The leak contained no technical details. At 19:30 UTC the PHP team published its pre-announcement early and moved the release forward from October 22 to October 21, keeping the 14:00 UTC slot. At around 20:00 UTC Calif accidentally published a video of its proof of concept, which was deleted quickly but kept circulating as copies. On October 21 at 07:41 UTC, more than six hours before the coordinated time, Chainguard published built images containing the fix.
The PHP Foundation accuses Chainguard of unilaterally breaking the embargo. Like other distributors, Chainguard had received the patch in advance, and with the images attackers could study the fix in binary form while everyone else was still waiting. Lorenc does not dispute the sequence of events, but he does dispute the accusation. His team had reproduced the bugs after a tip-off using its own test harness and an AI model and then helped test the patches. When the first proofs of concept appeared on social media on Tuesday and other vendors reported attacks, he decided late that night to ship and informed the coordination group immediately. Chainguard’s policy, he said, is “Coordinated vulnerability disclosure, unless there's evidence of active exploits in the wild”. He did not say which vendors had reported attacks, and he presented no evidence.
What I take from this is less a verdict on Chainguard than an observation about your operations. An embargo protects exactly as far as everyone involved keeps it, and this case had four leaks: the CVE numbers, the video, possibly the guidance for critical infrastructure operators and finally the early images. Whether the six hours actually helped attackers cannot be judged from the outside. For users of Wolfi and Chainguard images they meant a head start, but only for those whose pipeline picks up new image digests without a human in the loop. The timing of a patch is set by leaks, distributors and researchers, not by your maintenance window.
PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 and their side effects
The advisories explicitly name updating to a version with the patch as the only complete mitigation. The fixed versions are PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35, and they fix both flaws at once. After the update all workers must restart, otherwise the old code keeps running in memory. For PHP-FPM that means restarting the master, for mod_php restarting Apache, for containers a new image and a rollout.
FrankenPHP released version 1.13.2 on October 21. According to the release notes its Docker images are built with PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12 and the static binaries with PHP 8.5.12. If you run FrankenPHP as a static binary, you replace the binary. If you build your own image on a FrankenPHP base image, you rebuild and bump the tag or digest. In Wolfi, the package definitions in the wolfi-dev/os repository carry php-8.5 at version 8.5.12 and php-8.4 at version 8.4.27, which I checked directly in the YAML files on October 22. According to its security tracker, Debian has shipped php8.2 8.2.35-1~deb12u1 for Bookworm and php8.4 8.4.27-1~deb13u1 for Trixie (DSA-6574-1); Forky was still vulnerable on October 22. Amazon Linux 2023 patched php8.2 through php8.5 on October 22 with ALAS2023-2026-3301 to -3304, while no fix is planned for php8.1. On Amazon Linux 2 only the php8.2 extra is patched (ALAS2PHP8.2-2026-015); the php package from the core repository gets no fix. The Alpine tracker did not list the CVE yet on October 22. Distributions often patch by backport without adopting the upstream version number, in which case the version number alone tells you little.
The update changes the behaviour on memory exhaustion, and you should know this before rolling out. memory_limit becomes a soft limit: a request may exceed it slightly until the next VM check point before it aborts. If it breaks the hard limit from memory_hard_limit_percent, the process exits with code 137. In Kubernetes that code has so far meant a kill by the OOM killer or a SIGKILL. After the update it can also mean that PHP terminated itself, which I derive from the exit code and would keep in mind for alerts and dashboards. On ordinary memory exhaustion a patched PHP still aborts the request with the familiar fatal error, but it leaves no corrupted state behind. Only the hard limit ends the whole process.
There are no official binary releases for older branches. According to Threat Landscape and SOCRadar there are only minimal source backports for 7.4, 8.0 and 8.1, and some distributions and long-term-support vendors that received the patch in advance ship their own backports. For 7.3 and older, SOCRadar says, there is no fix at all. I do not consider unofficial community patch collections a viable path, because nobody vouches for their completeness. If you run such versions, take this case as the reason to upgrade.
Hardening beyond the patch
Before looking at individual measures, it helps to classify the problem. The bug lives in the interpreter itself and is triggered before your application even runs. Anything that checks at the application level therefore comes too late. Three classes of measures can work: those that take control over memory usage away from the attacker, those that limit state between requests, and those that contain a successful takeover inside the worker. The first two classes lower the likelihood, the third lowers the damage.
Request limits in front of PHP
The attack on CVE-2026-109618 relies on a request generating more memory than its size would suggest. A reverse proxy that limits body size takes away part of that room. In Caddy, and thus in FrankenPHP, the request_body directive with max_size does this, and according to the documentation reads beyond the limit end with status 413. In Traefik the Buffering middleware with maxRequestBodyBytes takes on this role. According to Daubois such limits mainly help with bodies without a declared length, which is exactly the case that bypasses the initial post_max_size check.
Against the other levers a plain size limit helps only so much, because many headers per part and many empty file fields also fit into a small body. The advisory therefore also recommends limiting the number of parts, headers per part and uploads at the frontend and lowering max_input_nesting_level. An ordinary reverse proxy can hardly express such structural limits; you need a WAF with multipart inspection for that. Where an application does not expect this kind of form data at all, for example pure JSON APIs, the simplest option is to reject multipart/form-data at the proxy for those paths. A TYPO3 backend needs uploads, a headless API often does not.
Memory limits for the interim
The interim measure the advisory lists first sounds counterintuitive: memory_limit=-1. Without a finite limit the attacker loses the predictable boundary the request is tailored to. According to the advisory the jump does not disappear entirely, though: if mmap() fails, for example, PHP still jumps. In PHP-FPM you set the value with php_admin_value in the pool, because applications then cannot turn it back via ini_set(), and you check that no pool, directory configuration or application sets a finite limit again. All workers then need a restart. The downside is obvious, since a single request can now take as much memory as it likes. As a replacement the advisory mentions a cgroup limit via memory.max, but warns that it does not guarantee a clean allocation failure and that each worker needs its own group so that the master and all workers do not die together.
This exact point becomes a trap in Kubernetes. A container’s memory limit is one cgroup for the whole container. With FPM in a container an overflow hits the master and all its children, with FrankenPHP the single process anyway. The interim fix therefore trades memory corruption for an availability risk that I would only accept for the hours until the patch. According to the advisory you should explicitly not use RLIMIT_AS or RLIMIT_DATA, because mmap() then fails and triggers exactly the vulnerable path.
Less state between requests
CVE-2026-109619 needs a consumer that reads stale state before initialisation, and the most important one can be switched off. With session.upload_progress.enabled=0 session upload progress goes away. The advisory explicitly recommends this even after the patch if you do not need the feature, and the PHP documentation has long advised it because the feature writes client-supplied file and field names unvalidated into the session store. According to the documentation the setting is INI_PERDIR, so it belongs in php.ini or the pool configuration, and only a worker restart makes it effective.
On PHP 8.5, fatal_error_backtraces=0 removes the producer of the confirmed RCE case. After the patch you can switch it back on if the backtraces help you with debugging. The most radical variant, pm.max_requests=1 in PHP-FPM, starts a fresh worker for every request and leaves stale state no successor. That costs so much performance, though, that it is only an option for small instances. For FrankenPHP in its default configuration the advisory did not establish an early consumer, but it stresses that this does not make it immune. Worker mode, in which an application deliberately stays in memory across many requests, is not analysed separately in the advisories. Regardless of that, every fatal error and every timeout you find in the logs and fix reduces the opportunities for a producer.
Retiring mod_php
The most dangerous path concerns mod_php, because shutdown runs there even after a failed startup and because Apache applies .htaccess directives with php_value before the request starts. PHP-FPM and FrankenPHP are not immune, and via upload progress the advisory even validated code execution against FPM. For CVE-2026-109618, however, no application-independent exploit is documented there. If you still run mod_php, that is a good reason to switch, especially since FPM separates the PHP process from the web server and allows separate users per pool. It is no substitute for the patch.
The worker as a prisoner
If a takeover succeeds anyway, the worker’s environment decides the damage. In a Kubernetes pod these are the familiar building blocks: runAsNonRoot, allowPrivilegeEscalation: false, dropped capabilities, seccompProfile: RuntimeDefault and the Pod Security Standard “restricted”. With readOnlyRootFilesystem: true and writable emptyDir volumes only for temporary files, sessions and caches, a web shell can store neither code nor binaries permanently. A minimal base image without a shell or package manager takes away the tools an attacker wants to continue with. None of these measures prevents the code execution itself, because it happens inside the legitimate PHP process, but they turn a takeover into a dead end.
An egress lockdown does the most good here. A NetworkPolicy with policyTypes: [Egress] that allows the PHP pod only DNS, the database, Valkey or Redis and the APIs it really needs prevents downloading further tools, a reverse shell and exfiltration of stolen data to a server of the attacker’s choosing. The operational cost is maintaining the allow-list, since every new external service needs a rule. It does not protect credentials the worker legitimately needs. Database password and encryption key must be treated as compromised after a takeover. How egress rules, Pod Security and secrets fit together for TYPO3 in practice is covered in the series TYPO3 on Kubernetes under IT-Grundschutz.
Measures that do not help
Some familiar PHP hardening measures do not work against this mechanism. PHP enforces disable_functions and open_basedir inside the respective PHP functions. An attacker who executes native code in the process through memory corruption never calls those functions in the first place and so bypasses their checks. I derive this from how they work. According to the advisory, error_reporting, the @ operator, display_errors and log_errors do not protect either, because the INI consumer works regardless of whether a warning is displayed or logged. Daubois also points out that disabling upload progress helps against CVE-2026-109619 but not against CVE-2026-109618.
WAF rules that protect application logic, updates to TYPO3 extensions and clean application code change nothing either, because the attack takes place before the first byte of application code. Finally, a CVE scanner can be wrong in both directions. It reports patched distribution packages with an old version number as vulnerable and misses a custom binary whose version it does not know. So rely on the package source and the changelog, not only on the string behind php -v.
Detection and verification
The version is the first thing that tells you whether you are affected. Check with php -v, php-fpm -v or frankenphp version in every container image and on every host, not just the one you happen to have in mind. For distribution packages the changelog is what counts: if CVE-2026-109618 appears there, the backport is in, even if the version number looks older. After that, look at the configuration that matters for the interim period, namely memory_limit, session.upload_progress.enabled and on 8.5 fatal_error_backtraces, each in the configuration actually in effect for the web SAPI rather than the CLI.
Whether someone has attacked you is harder to tell, because the PHP team has not published any indicators, and the advisory explicitly warns that clean logs do not prove you are safe. I see three plausible traces, all of which I derive from the mechanism. Bursts of “Allowed memory size … exhausted” on multipart POSTs from the same source fit attempts to provoke memory exhaustion deliberately. Worker crashes, shown in the FPM log as “exited on signal 11” and in the Apache log as a segmentation fault, fit failed attempts with corrupted memory. And after a successful attack, child processes of the web worker that start a shell, curl or wget stand out, which SOCRadar also recommends as a detection rule. In addition, check for new PHP files in the web root and writable directories as well as new cron jobs.
If you suspect a compromise, the order is isolate, patch, rebuild. CERT-EU recommends separating internet-facing applications from the public network if an immediate update is not possible. Afterwards you do not repair the worker by hand but rebuild it from a clean, patched image, rotate database credentials, encryption keys and API tokens from the configuration, and review the logs from October 20 onwards.
Recommendation for operators
Act now if PHP before 8.2.35, 8.3.36, 8.4.27 or 8.5.12 serves requests from the internet, whether through mod_php, FPM or FrankenPHP. mod_php is the most urgent, followed by every instance with uploads and forms. Install the update today, restart all workers and rebuild your images. If that is not possible immediately, switch off upload progress, on 8.5 also fatal_error_backtraces, limit request size and multipart at the proxy and, if necessary, take the instance off the network.
Monitoring is enough only where PHP runs exclusively as a CLI for internal jobs and parses no data from outside. Even then the update belongs in the next maintenance window, because in my experience such deployments change faster than their documentation.
For everything else, the advice I give for every vulnerability applies, and this case makes the argument for me. Patches and updates should be automated. When Renovate or Dependabot propose new base images for PHP or FrankenPHP and new digests of your Wolfi images as merge requests on their own, and the pipeline tests them against a staging environment, the October 21 release was a matter of hours. With Chainguard images, the fix would even have reached production before the official release time. A cooldown for routine updates protects against compromised releases, and security updates like this one are exempt from it. The changed semantics of memory_limit then show up in testing, where a load test ending with exit code 137 is harmless, not in production. Updating by hand, you might have read the warning on Tuesday evening and, in the worst case, applied the update only after your holiday, together with everything else that piled up in the meantime.
Frequently asked questions about PHP2Shell
Am I affected if I use FrankenPHP?+
Yes. FrankenPHP embeds the affected PHP core and is considered likely vulnerable according to the advisory. Update to FrankenPHP 1.13.2, which is built with PHP 8.5.12 and the other patched versions, and rebuild your images.
Is memory_limit=-1 enough protection?+
What about PHP 7.4, 8.0 and 8.1?+
There are no official releases for these branches. According to Alexandre Daubois of the PHP security team the mechanism goes back to PHP 5.3, so you should assume you are affected and rely on a backport from your distribution or an upgrade.
Was Chainguard wrong to ship early?+
That depends on how you weigh the reports of attacks on Tuesday night, and Chainguard has not substantiated them. For your own operations the more important question is whether your pipeline picks up a fix as soon as it appears anywhere.
Conclusion
PHP2Shell is not an exotic parser bug but the result of a shortcut in error handling that spread into almost every corner of the interpreter over the years. A non-local jump out of a C function leaves everything exactly as it was at that instant, and a long-lived worker carries that state into the next request. The lesson reaches beyond PHP. Wherever a runtime handles errors with a jump and reuses processes, it is worth asking what still runs after the error and who reads the state afterwards. The second lesson concerns operations: the date of a patch is not yours to set, and this time less than 24 hours passed between leak and fix. You are only prepared for that if you can roll out updates without manual work.
Sources
- GitHub Advisory GHSA-w8hw-w9fx-j79w: RCE via OOM corruption (CVE-2026-109618)
- GitHub Advisory GHSA-6wmf-4rv5-p3rp: RCE via stale global state (CVE-2026-109619)
- php-src fix commit 3584a98: Avoid state corruption via bailout
- PHP Foundation: Today's PHP Security Release, and How We're Strengthening PHP Security
- Alexandre Daubois: What the PHP2Shell rumors got wrong, from inside the PHP security team
- oss-security: CVE-2026-109618
- FrankenPHP releases (v1.13.2)
- Socket: PHP Foundation Says Chainguard Broke Security Embargo
- The Register: PHP blames Chainguard
- Threat Landscape: PHP Core RCEs Leak Early
- Infosecurity Magazine: Critical PHP Vulnerabilities Leaked
- SOCRadar: PHP2Shell
- PHP manual: error handling runtime configuration (fatal_error_backtraces)
- PHP manual: session configuration (session.upload_progress.enabled)
- Caddy docs: request_body
- CISA Known Exploited Vulnerabilities Catalog
I check your PHP and TYPO3 platform for vulnerable runtimes, put request limits and container hardening in place and build the pipeline that rolls out a fix like this one in hours.
PHP and FrankenPHP audits, egress rules and Pod Security for TYPO3 on Kubernetes, update automation with Renovate for base images and Wolfi digests.
Platform operations instead of advice on paper: I continuously check, patch and harden your infrastructure.
