Skip to content

fix(dingtalk): accept oapi.dingtalk.com webhook domain for stream mode reply routing#9608

Closed
audanye-sudo wants to merge 1 commit into
NousResearch:mainfrom
audanye-sudo:fix/dingtalk-webhook-domain
Closed

fix(dingtalk): accept oapi.dingtalk.com webhook domain for stream mode reply routing#9608
audanye-sudo wants to merge 1 commit into
NousResearch:mainfrom
audanye-sudo:fix/dingtalk-webhook-domain

Conversation

@audanye-sudo

Copy link
Copy Markdown

Summary

DingTalk Stream SDK returns sessionWebhook URLs using the oapi.dingtalk.com domain, but the current SSRF validation regex (_DINGTALK_WEBHOOK_RE) only accepts api.dingtalk.com. This causes all reply routing via session webhooks to silently fail when running in stream mode — messages are received but replies never reach the user.

Root Cause

The webhook validation regex at gateway/platforms/dingtalk.py:57 was:

_DINGTALK_WEBHOOK_RE = re.compile(r'^https://api\.dingtalk\.com/')

DingTalk's Stream SDK actually returns webhooks like:

https://oapi.dingtalk.com/robot/sendBySession?session=xxx

The oapi.dingtalk.com domain is the legacy but still actively used Open API endpoint, while api.dingtalk.com is the newer endpoint. Both are legitimate DingTalk domains.

Fix

Updated the regex to accept both domains:

_DINGTALK_WEBHOOK_RE = re.compile(r'^https://(?:api|oapi)\.dingtalk\.com/')

This is a minimal, targeted fix — no behavioral change for api.dingtalk.com webhooks; only oapi.dingtalk.com is additionally accepted.

Additional Fix

Fixed the Docker troubleshooting docs (website/docs/user-guide/docker.md): the version check command used docker run which spins up a new container instead of checking the running one. Corrected to docker exec hermes hermes version.

Commits

Commit Scope
fix(dingtalk): accept oapi.dingtalk.com webhook domain alongside api.dingtalk.com gateway/platforms/dingtalk.py, website/docs/user-guide/docker.md

Test Plan

  • Verified regex matches both https://api.dingtalk.com/... and https://oapi.dingtalk.com/...
  • Verified regex rejects non-DingTalk domains (SSRF protection intact)
  • Tested DingTalk stream mode end-to-end: bot receives messages and replies successfully via oapi.dingtalk.com session webhooks
  • Docker docs command verified: docker exec correctly queries the running container

Risk Assessment

Low risk — single regex change expanding the allowlist to include a legitimate DingTalk domain. No new dependencies, no architectural changes, no breaking changes.

…dingtalk.com

DingTalk Stream SDK returns session webhooks using oapi.dingtalk.com domain,
but the SSRF validation regex only accepted api.dingtalk.com. This caused all
reply routing via session webhooks to silently fail in stream mode.

Also fixes docker.md version check command to use `docker exec` instead of
`docker run` which would start a new container.
@meng93

meng93 commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

good change

@audanye-sudo

Copy link
Copy Markdown
Author

Hey folks 👋

Just want to give some context on this PR and the other two DingTalk PRs I'm submitting together (#9609, #9610), since DingTalk might not be familiar to everyone here.

What is DingTalk?

DingTalk (钉钉) is basically the "Slack/Teams of China" — it's an enterprise communication platform by Alibaba with 700M+ registered users and is the dominant workspace app across Chinese enterprises. Think of it as Slack + Zoom + HR tools + low-code platform all in one. For Hermes Agent, DingTalk support means opening up the bot to a massive user base in the Chinese market.

Current situation: DingTalk integration is completely broken

Right now, the DingTalk adapter in Hermes has two blocking bugs that make it literally unusable end-to-end:

  1. This PR (fix(dingtalk): accept oapi.dingtalk.com webhook domain for stream mode reply routing #9608) — The webhook domain validation rejects oapi.dingtalk.com, which is the domain the Stream SDK actually uses for session webhooks. So even if messages come in, replies never go out. Silent failure, no error, just... nothing happens from the user's perspective.

  2. fix(dingtalk): adapt message handler to dingtalk-stream SDK CallbackMessage format #9609 — The message handler reads fields from the wrong object layer. The SDK gives you a CallbackMessage where all the good stuff (text, sender, webhook) is inside .data, but the code reads from the top level — so every field is empty. Messages come in and immediately get dropped as "empty message, skipping."

These two together mean: users who try to set up DingTalk today will see the bot "online" but it won't respond to anything. That's a pretty bad first impression.

This specific PR is the simpler of the two fixes — just a one-line regex change to accept both api.dingtalk.com and oapi.dingtalk.com as legitimate webhook domains. Minimal change, no risk to other platforms.

@RuckVibeCodes RuckVibeCodes left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[gus-first-pass] fix(dingtalk): accept oapi.dingtalk.com webhook domain for stream mode reply routing - Clear fix, no issues found.

@Jiangxuejian Jiangxuejian left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works on my WSL2. (Hermes Agent v0.9.0 (2026.4.13))

@teknium1

Copy link
Copy Markdown
Contributor

Closing — the oapi.dingtalk.com webhook domain is now accepted on main as of #11471 (#11471). Thanks for catching and reporting this.

@teknium1 teknium1 closed this Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants