A new demonstration shows that an AI-assisted workflow can port a pre-authentication remote code execution exploit to a vulnerable WAGO programmable logic controller, allowing arbitrary ARM shellcode to run without valid credentials.
The research documented by Forescout shows meaningful progress in AI-enabled exploitation of operational technology but also reveals that the process remains expensive, error-prone, and heavily dependent on human reverse-engineering expertise.
The experiment targeted CVE-2021-31886, a buffer-overflow vulnerability in the Nucleus FTP server used by certain embedded systems, including affected WAGO PLCs.
Claude AI Creates Pre-Auth RCE Exploit for WAGO PLC
The flaw occurs because the FTP service fails to adequately validate the length of a username supplied through the USER command. An attacker able to reach the vulnerable FTP service could use an oversized username to overwrite memory.
In Forescout’s test, that capability resulted in arbitrary ARM shellcode executing on a WAGO 750-831 PLC running firmware version V01.04.16. The proof of concept required no FTP authentication because the vulnerable processing occurs before login.
The successful payloads reportedly executed in the PLC’s Ethernet receive callback context, causing the device to generate outbound ICMP echo requests and UDP packets containing a test message.
Forescout began with an existing exploit for a related WAGO 750-852 model, then tasked Claude Code with adapting it to the 750-831. The AI had access to the target firmware, a live PLC, Ghidra, Python, terminal tools, and the reference exploit.
Claude initially identified an apparently separate potential vulnerability in the firmware’s FTP parsing logic, but researchers redirected the work toward the known CVE-2021-31886 flaw.
It then used static firmware analysis and live FTP probing to identify the device architecture, firmware base address, vulnerable function chain, and target-specific memory locations.
The difficult phase was not crashing the PLC. Claude was able to produce a crash condition relatively early. The challenge was achieving repeatable, controlled code execution while ensuring the injected shellcode remained intact long enough to run.

Forescout found that normal FTP processing cleared the attacker-controlled buffer after parsing the USER command. Claude eventually identified that the exploit path needed to avoid the normal command-completion behavior.
With researcher-provided disassembly context, the model adapted the command sequence to preserve the shellcode buffer until execution.
The final RCE-development stage lasted 8 hours and 32 minutes across several days and consumed $535.74 in API usage. Forescout said the work involved roughly 2,600 input tokens and 1.3 million output tokens. Human guidance remained essential.
Researchers had to correct false leads, provide additional disassembly details, point the model toward relevant code paths, and steer it away from unrelated analysis. Several attempts failed or exceeded the context window limit before the root cause of the shellcode overwrite was understood.
The team also attempted to use the working RCE as a foundation for a more capable command-and-control implant. That effort ended when a payload wrote to the flash-mapped memory, permanently bricking the physical PLC.
Instead, it demonstrates that AI can accelerate elements of low-level embedded exploit development when paired with expert operators, tools, firmware access, and a live target.
For defenders, the central lesson is that “difficult to exploit” should not be treated as a permanent mitigating control.
Organizations should restrict unnecessary exposure of PLC services, particularly FTP, Telnet, and web management, segment OT networks, monitor for unexpected outbound traffic and repeated crashes, and test incident-response plans against rapidly adapted, AI-assisted attack paths.
Give your security team the visibility and context to investigate suspicious activity faster and contain threats before business impact grows. Strengthen Your Investigations with ANY.RUN