July 21, 2026
Hiding in Plain Sight
Chinese messaging gateways in forked agent harnesses — and why “we don't use them” is not a security posture.

Jeffery Myers · Founder & Chief Imagineer, HumanAIFusion & HannahLabs
SPS-ART-china-gateways-2026-001 · TLP:CLEAR · Basis: NousResearch hermes-agent ≤ v0.18.2 (2026-07-08)
Chinese messaging gateways in forked agent harnesses — and why “we don't use them” is not a security posture.
§ 01 · Summary
The Short Version
A team that hard-forks an agent harness for its harness, its memory architecture, and its skill system does not fork those things in isolation. It forks a tree. And somewhere in that tree — first-party, in-repo, compiled and linked alongside the code that was actually wanted — sits a set of messaging gateways for Chinese platforms: DingTalk, Feishu/Lark, WeCom, Weixin, QQBot, and Yuanbao.
Those gateways don't go away because they went unwanted. Disabling a channel in a config file is not the same as removing its code path. Dormant connector code is still reachable surface, still a shipped dependency, and still something an auditor — or an attacker — finds in the tree. This article is about what that inherited code actually is, why it is a sharper problem than the same code would be upstream, and what a fork owner has to do about it.
Disabling a channel in a config file is not the same as removing its code path.
The frame here is deliberately not “Chinese software is bad.” That frame is lazy, and it leads to the wrong controls. The real problems are three, and they are mechanical: these are terminal-capable inbound command channels that went unaudited; they route agent I/O to infrastructure the operator does not control and cannot observe; and, as inherited-but-unused code, they are the part of a fork least likely to receive the fixes upstream is quietly shipping. Deployment posture determines safety, not the nationality on the package label.
§ 02 · Inventory
What Actually Ships
Modern agent harnesses in this lineage run a single gateway process that connects to every configured platform at once — “one process, many front doors.” In the current hermes-agent tree the per-platform adapters live under gateway/platforms/, and the Chinese-market set is unambiguous and first-party:
| Adapter | Platform |
|---|---|
dingtalk.py | DingTalk (钉钉, Alibaba) — over WebSocket |
feishu.py | Feishu / Lark (飞书, ByteDance) — WebSocket or webhook, with a companion feishu_comment.py document-comment handler |
wecom.py | WeCom / WeChat Work (企业微信, Tencent) — callback mode |
weixin.py | Weixin / personal WeChat (微信, Tencent) — via the iLink Bot API |
qqbot/ | QQ Bot (Tencent QQ) — a sub-package with its own adapter, crypto, and keyboard modules |
yuanbao.py | Yuanbao (腾讯元宝, Tencent's AI app) |
Two facts about these adapters matter more than the list itself.
First, they are wired for terminal access. In the upstream configuration model each of these per-platform toolsets is provisioned with the full toolset — including terminal execution. That is the whole point of the harness: a message from one of these channels can become a shell command on the host.
These are not read-only chat bridges. They are remote-command front doors that happen to speak a messaging protocol.
Second, the safe defaults are thinner than the marketing implies. The upstream gateway does ship a genuine default-deny: unknown users are rejected unless they are on an allowlist or have completed DM pairing. That is the right default for a bot that can run commands. But default-deny is only as good as its uniform enforcement across every adapter — and, as we will see, at least one of these Chinese adapters historically shipped a setup path that wrote an allow-all flag by default, quietly inverting that protection for anyone who stood the channel up.
A fork inherits all of this. Every adapter module, every toolset registration, every default. The question a fork owner has to answer is not “do these channels exist upstream” — they plainly do — but “did the fork excise this code, or merely leave it unconfigured?” Those are different security postures, and only one of them survives an audit.
§ 03 · Posture
The Indifference Problem
There is a second failure mode that runs deeper than the geopolitical laziness. It is indifference.
A team that inherits these adapters and decides not to use them often stops thinking about them entirely. The adapters are unconfigured, so they are dormant, so they are safe — that is the logic. And from that logic flows a kind of institutional disinterest: nobody watches the code, nobody reviews it, nobody patches it, nobody even asks what it does. The channels are not removed, they are simply ignored.
Ignored code is the code most likely to harbor surprises.
This indifference is particularly corrosive because it is self-reinforcing. An unconfigured adapter does not show up in threat models, does not appear in security reviews, does not surface in vulnerability scanners — which look at active configurations, not dormant code. So the team develops a confident sense that the problem does not exist. That confidence is exactly backwards. An unconfigured adapter is a code path that will never be watched, never be patched on the fork's own schedule, never surface in the team's observability stack if something goes wrong. It is the definition of an unowned attack surface.
The indifference becomes especially dangerous in the context of silent fixes. When the upstream ships a hardening commit with no CVE, the machinery that ordinarily alerts a team — scanners, feeds, dependency alerts — says nothing. For a dormant channel the team has decided does not matter, the commit passes silently into the upstream's history, and the fork's divergence grows by one more line without anyone noticing or caring. That is how a team can carry a fail-open authentication validator, or an allow-all default, or a path-traversal bug, indefinitely — not because the upstream failed to fix it, but because the team's indifference created a gap the fixes could slip through.
§ 04 · Threat Model
Why These Are Not Just More Telegram
A reasonable objection: the harness also ships adapters for Telegram, Discord, Slack, Signal, and WhatsApp. Why single out six files? Because three properties stack on the Chinese-market adapters that do not stack the same way elsewhere.
An inbound untrusted-command channel outside the threat model
Any live messaging gateway is a prompt-injection and command-injection surface into the agent loop. The channels a team actively runs, it watches. The channels it “isn't using” but still ships are the dangerous ones precisely because nobody is watching them — no allowlist review, no log tailing, no anomaly baseline.
Egress to infrastructure the operator can't see into
A WeCom callback terminates against qyapi.weixin.qq.com; a WeCom long-connection rides openws.work.weixin.qq.com; Weixin authenticates through Tencent's iLink API. An observability stack sees the agent making an HTTPS call. It does not see what the far side does with the payload, and it never will.
Provenance that went unvetted
Several connectors in this broader ecosystem are authored by the platform vendors themselves rather than by neutral maintainers — the official WeChat bridge for the sibling OpenClaw project ships as a Tencent-published package. Vendor-authored connectors are not inherently malicious, but they are a supply-chain trust decision, and inheriting one through a fork means making that decision without knowing it was being made.
An unmonitored terminal-capable front door is worse than a monitored one — and inherited-but-unused is the definition of unmonitored.
None of this requires a conspiracy. It requires only that a project is now shipping terminal-capable code that talks to systems it cannot audit, on channels nobody is watching, from a vendor it did not choose. That is a posture problem, and posture is the whole game.
§ 05 · Evidence
The Evidence Is Already in the CVE Record
This is not theoretical hardening against a hypothetical bug. The Chinese-market adapters in this lineage have a published vulnerability history, and it clusters around exactly two failure classes: path traversal / arbitrary file read, and authentication that fails open.
Start with the harness most of these forks descend from. Hermes-agent's own WeChat Work adapter carries CVE-2026-7396: a path-traversal flaw (CWE-22) in gateway/platforms/wecom.py in version 0.8.0. It is remotely exploitable, needs no authentication and no user interaction, has a public exploit, and at disclosure had no vendor fix. That is the exact file these forks descend from.
It does not travel alone. The same disclosure window produced a cluster of authentication defects in the gateway core the adapters sit on:
CVE-2026-7112Improper authentication in _check_auth in gateway/platforms/api_server.py (the API-server-key handler), remotely reachable.
CVE-2026-7113Missing authentication via the _INSECURE_NO_AUTH argument in gateway/platforms/webhook.py.
CVE-2026-10548Improper authentication in agent/credential_pool.py, affecting versions up to 2026.4.23, disclosed June 2026.
A detail worth pausing on: several of these records note that the project was told early, often through a pull request, and had not responded at time of publication. That is the disclosure-gap pattern, and it is a fork owner's problem twice over — once because the upstream fix may be slow, and again because even when it lands, nothing pushes it into the fork's tree.
Now look sideways, at the sibling project OpenClaw, whose adapters share direct lineage with these — the live feishu.py in hermes-agent even carries rate-limit and anomaly-tracking constants annotated as matching OpenClaw. The parallels show the severe end of the same failure classes:
CVE-2026-44109CVSS 9.2 · CRITICALAn authentication bypass in OpenClaw's Feishu / Lark plugin. Two fail-open logic inversions — in the webhook signature validator and the card-action replay guard — let an unauthenticated attacker inject arbitrary events into the command-dispatch engine. The root cause is as blunt as security bugs get: a missing encryption key caused the validator to return true — auth passed for everyone. With execution tools enabled, that is unauthenticated remote code execution at the process's privileges.
CVE-2026-43533CVSS 8.6 · HIGHA path traversal in OpenClaw's QQBot extension. Media tags in reply text resolved to local file paths without boundary enforcement, so ../ sequences escaped the media directory and the bot read and exfiltrated arbitrary host files. Network-exploitable, no authentication.
Different projects, same two failure classes, same corner of the codebase.
Feishu auth-bypass-to-RCE. QQBot path-traversal-to-file-read. WeChat Work path traversal. When the identical bug class shows up in the identical component across sibling projects, the correct inference is not “unlucky” — it is “this surface is systematically under-hardened relative to the mainstream channels.” And it is the surface a fork inherits without choosing to.
§ 06 · Patching
The Silent Fixes Are the Dangerous Ones
Here is the part that turns an ordinary patch-management story into a fork-specific hazard. Read the upstream gateway commit history and security-relevant fixes appear — landing on the Chinese adapters — that were never assigned CVEs.
Feishu — an authentication triple
Pull requests #30739 / #30744 / #30746 plus a consolidating commit: the URL-verification token was being echoed before the challenge, webhook-secret validation was made mandatory, and approval buttons were bound to their originating chat. Same fail-open class as OpenClaw's Critical CVE-2026-44109 — closed here silently, with no advisory. No CVE.
DingTalk — default-allow-all removed
The setup routine had been auto-writing a DINGTALK_ALLOW_ALL_USERS=true flag — the channel accepted inbound commands from any user, on a terminal-capable adapter, until a commit stopped it. No CVE.
QQBot — session-owner authorization added
Approval buttons gained session-owner authorization. No CVE.
WeCom — delivery race-condition fix
A delivery race-condition fix, distinct from the CVE-tracked path traversal. No CVE.
For a fork, a silent fix is more dangerous than a CVE.
A CVE shows up in a scanner, in dependency alerts, in every vulnerability feed a team subscribes to. A quiet commit that hardens feishu.py shows up in exactly one place — the upstream git log the fork is no longer merging. The vulnerability-tracking machinery that protects everyone else routes around a fork the moment it hard-forks, and it routes around it hardest on the components the team thought it wasn't using.
So the true exposure of a fork is not “which CVEs affect the pinned version.” It is “which of the upstream's un-CVE'd security commits is it missing, on adapters nobody audited, that no feed will ever surface.” That question is only answerable by diffing the tree against the upstream security commits by hand.
§ 07 · Consequence
The Fork Math: The Merge-Base Is the Attack Surface
Everything above sharpens to a single number: the commit a fork branched from.
The Chinese adapters entered this harness across many releases. The merge-base therefore determines which of these a fork even has — and in what state of hardening:
| Release | Adapters added |
|---|---|
earlier | Feishu, WeCom, and DingTalk |
~v0.9.0 | Native WeChat and WeCom callback mode |
v0.11.0 | QQBot |
v0.12.0 | Yuanbao |
Branch before the Feishu auth triple and the fork carries the fail-open validator. Branch before the DingTalk commit and it carries allow-all-by-default. Branch before the WeCom fix and it carries CVE-2026-7396.
The merge-base is the attack surface.
And the ground is moving fast underneath. The upstream is not a slow-moving dependency a team can pin and forget.
SPS-ART-china-gateways-2026-001 · TLP:CLEAR · © 2026 HumanAIFusion & HannahLabs