HumanAIFusion
Back to the Journal

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.

Hiding in Plain Sight

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:

AdapterPlatform
dingtalk.pyDingTalk (钉钉, Alibaba) — over WebSocket
feishu.pyFeishu / Lark (飞书, ByteDance) — WebSocket or webhook, with a companion feishu_comment.py document-comment handler
wecom.pyWeCom / WeChat Work (企业微信, Tencent) — callback mode
weixin.pyWeixin / 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.pyYuanbao (腾讯元宝, 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-7112

Improper authentication in _check_auth in gateway/platforms/api_server.py (the API-server-key handler), remotely reachable.

CVE-2026-7113

Missing authentication via the _INSECURE_NO_AUTH argument in gateway/platforms/webhook.py.

CVE-2026-10548

Improper 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 · CRITICAL

An 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 · HIGH

A 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:

ReleaseAdapters added
earlierFeishu, WeCom, and DingTalk
~v0.9.0Native WeChat and WeCom callback mode
v0.11.0QQBot
v0.12.0Yuanbao

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

Share this article