T06 · System Persistence
- Location
dingtalk_unread_monitor.py:230- Finding
Automatic Installation of a Hidden Login-Persistence Watchdog
- Content
View full analysis
0 Then MsgBox "DingTalk launche ...[truncated 2554 chars]- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is disclosed as a DingTalk auto-replier, but it needs Review because it can persistently run in the background, read workplace context and local data, and send messages as the user without per-message approval.
Install only if you intentionally want a background tool that can monitor DingTalk, read related workplace/local context, and send single-chat replies as you. Use DRY_RUN and TEST_MODE first, disable or narrow Bash/web/local-code/gbrain access where possible, avoid enabling startup persistence until you understand the VBS watchdog, and make sure you have a way to remove the Startup launcher and PATH changes.
dingtalk_unread_monitor.py:230Automatic Installation of a Hidden Login-Persistence Watchdog
gen_launcher.py:184Persistent Modification of the Current User PATH During Monitor Setup
reply.py:482Untrusted DingTalk Content Reaches an Agent with Permission Bypass, Shell, File, and Network Capabilities
The skill is designed to send impersonated replies and retrieve local/chat-derived context, but the README does not prominently warn about privacy, consent, reputational harm, and account-impact risks. Users may enable it without understanding that it can act as them and consult sensitive data to craft messages.
The documented workflow is intentionally deceptive: it replies in the user's voice, silently consults private records, and specifically says not to reveal the lookup. This strips recipients of context about how the answer was produced and enables covert surveillance-backed impersonation in workplace communications.
The README states that reply generation and image recognition are sent through the CodeBuddy Agent SDK backend, but it does not clearly disclose that chat text and image contents may leave the local machine for processing. This creates a significant privacy and compliance risk, especially for workplace conversations and images.
The documentation explicitly allows the agent to query colleague contact records and message history via dws in order to formulate replies. That exceeds a narrow auto-reply scope and grants access to private organizational communications, creating privacy, surveillance, and unauthorized-use risks.
Allowing the agent to invoke Bash to query dws contact and sender history provides a broader, more powerful capability set than is needed for auto-reply. Shell-mediated access can enable unreviewed data gathering and makes it easier for prompts or tool misuse to traverse private workplace records without user awareness.
The skill is explicitly designed to inspect coworkers' chat/contact history and then generate replies as if written by the user. Combining covert data retrieval with impersonated messaging is dangerous because it can disclose private workplace information, violate consent expectations, and produce authoritative-seeming statements based on sensitive records.
声明描述的核心能力是“监听钉钉未读 + AI 自动回复/提醒”,涉及钉钉会话处理、消息判断、回复生成与通知行为。但提供的代码片段完全没有出现钉钉、会话、消息、微信、回复生成或触发处理逻辑。相反,它仅执行本地环境配置工作:枚举候选 Python、通过子进程测试是否安装 codebuddy-agent-sdk、导入 runtime 获取默认配置、读取和写入 .env。虽然这类脚本可能是整个技能的辅助安装组件,但就该代码片段本身而言,其实际行为与声明用途明显不一致,且包含未在声明中体现的本地环境探测与配置写入能力。因此应判定为描述与代码行为不匹配。
声明的核心功能是“监听钉钉未读消息并自动回复或提醒”,但提供的代码文件 vision.py 仅实现视觉识别层:读取图片路径,构造多模态消息,请求 CodeBuddy SDK 生成图片中文描述,并支持批量图片处理。代码没有任何钉钉会话读取、消息监听、自动发送回复、微信提醒、联系人名单过滤等逻辑,也未体现相关触发器或资源访问。该代码的主要目的与声明用途明显不一致,属于实质性描述与行为不匹配。
The skill is designed to send AI-generated messages as the user and even includes a recovery path that can true-send missed replies, but it lacks a prominent up-front warning about impersonation, external communication, privacy exposure, and business risk. Users could enable or invoke it without understanding that it may autonomously speak on their behalf.
The core documented behavior is to have AI automatically reply in the user's identity while suppressing self-identification and using bypassed permissions. This is deceptive impersonation by design, and if abused it can mislead coworkers, authorize actions falsely, disclose sensitive information, or create legal and workplace harm.
The top-level description immediately frames the skill as useful automation, but does not lead with a short warning that it continuously monitors chats, sends content to AI backends, and may transmit replies externally. For a skill that acts in the user's identity, this omission materially increases misuse risk.
The setup flow explicitly writes SDK environment declarations into .env, and elsewhere the document includes API key usage in the same private config. Consolidating runtime routing and credentials in one file is operationally convenient but increases the risk of secret exposure through accidental reads, logs, or overly broad agent file access.
├── gen_launcher.py # 启动器生成器(本机自动生成 Startup .vbs,.vbs 不随包分发) ├── dingtalk-helper-backup.md # 【方案B·人设干净部署模板】dingtalk-helper.md 的占位版(无私人数据),随 skill 移植;新机器未注册 agent 时自动兜底注入 ├── _validate.py # 自测脚本(7 模式:集成 / --inject / --test-guard / --test-construct / --test-statemachine / --test-mcp / --env,不真发回复;--env 做环境预检) ├── _setup_env.py # 安装脚本:探测并写入 SDK 运行环境(CODEBUDDY_SDK_PYTHON 等)到 .env ├── recover_missed.py # 补发漏掉的消息(监控曾宕机/DRY_RUN 时,手动拉未读并代复) └── stop_monitor.ps1 # 精确结束本脚本 python(仅停进程,Windows 用)
Referenced artifact was not completely inspected
N_NAMES`),同事/名单用中性占位(如「同事甲」)或 `.env` 变量,禁止把真实姓名写进 `.py` 注释、`_validate.py` 测试样例、`SKILL.md` 正文等任何位置。改代码后自查:凡 `温*`/`蔡*`/真实拼音全名等一律清零。
The prompt-locking explicitly forces the model to pose as a normal employee and forbids it from behaving like an assistant. That is an intentional deception mechanism designed to conceal AI involvement and increases the chance of persuasive fraudulent communication.
This duplicate finding points to the same behavior: implicit access to global MCP configuration and tokens. In the context of an autonomous reply agent, silent inheritance of external service credentials is dangerous because it broadens both reachable data and exfiltration channels.
- **⚠️ prompt 指令与工具挂载状态严格一致(防悬空指令)**:拼进 `_MODE_LOCK` 的知识库指令由 `build_knowledge_instruction()` 动态生成,与 `mcp_servers` 挂载判断**都读 `runtime.GBRAIN_GROUNDING` / `runtime.GBRAIN_MCP_URL` 同一实时来源**——gbrain 已挂载则写「必须先调 gbrain、失败回退本地」;gbrain 未挂载(`=0` 或无端点)则明确写「gbrain 未启用、不要调它,直接走本地文件」。绝不会出现「让 agent 去调一个不存在的工具」的悬空指令。
- 控制开关(均在 `runtime.py`,风格对齐 `TABLE_GROUNDING`):
- `GBRAIN_GROUNDING`(默认开,`=0` 关):关闭则 prompt 切本地文件模式 + 不挂 gbrain 工具,退回纯人设代复(仍保留本地 `产品资料/` `项目文件/` 保底)。
- `GBRAIN_MCP_URL` / `GBRAIN_MCP_TOKEN`:缺省时**自动从 `~/.workbuddy/mcp.json` 的 `gbrain` 条目读取**(url + Bearer token),单一真源、无需重复填 token;也可用环境变量覆盖。
- `_MODE_LOCK` 与 `dingtalk-helper.md` 均写明「**gbrain 优先(事实性问题必须)、本地文件保底**」:事实性且需要的内容才调 `mcp__gbrain__search`/`query`;**若 gbrain 未接入 / 调用失败 / 超时 / 检索结果为空或明显不对题,回退**到工作空间本地 `产品资料/` `项目文件/` 文档用 Grep/Glob/Read 核实。两路都查不到才如实说「这个我得查下资料确认,稍回你」。本地文件是保底、并非禁用(之前"禁止读本地"的过激限制已撤销)。
- 知识入库:**优先**把产品手册/项目文档/记忆整理进 gbrain(见 gbrain 自身文档)做主检索源;工作空间 `产品资料/` `项目文件/` 文档树**保留作保底回退**,仍随工作空间维护、不要删。
This duplicate finding points to the same behavior: implicit access to global MCP configuration and tokens. In the context of an autonomous reply agent, silent inheritance of external service credentials is dangerous because it broadens both reachable data and exfiltration channels.
- **⚠️ prompt 指令与工具挂载状态严格一致(防悬空指令)**:拼进 `_MODE_LOCK` 的知识库指令由 `build_knowledge_instruction()` 动态生成,与 `mcp_servers` 挂载判断**都读 `runtime.GBRAIN_GROUNDING` / `runtime.GBRAIN_MCP_URL` 同一实时来源**——gbrain 已挂载则写「必须先调 gbrain、失败回退本地」;gbrain 未挂载(`=0` 或无端点)则明确写「gbrain 未启用、不要调它,直接走本地文件」。绝不会出现「让 agent 去调一个不存在的工具」的悬空指令。
- 控制开关(均在 `runtime.py`,风格对齐 `TABLE_GROUNDING`):
- `GBRAIN_GROUNDING`(默认开,`=0` 关):关闭则 prompt 切本地文件模式 + 不挂 gbrain 工具,退回纯人设代复(仍保留本地 `产品资料/` `项目文件/` 保底)。
- `GBRAIN_MCP_URL` / `GBRAIN_MCP_TOKEN`:缺省时**自动从 `~/.workbuddy/mcp.json` 的 `gbrain` 条目读取**(url + Bearer token),单一真源、无需重复填 token;也可用环境变量覆盖。
- `_MODE_LOCK` 与 `dingtalk-helper.md` 均写明「**gbrain 优先(事实性问题必须)、本地文件保底**」:事实性且需要的内容才调 `mcp__gbrain__search`/`query`;**若 gbrain 未接入 / 调用失败 / 超时 / 检索结果为空或明显不对题,回退**到工作空间本地 `产品资料/` `项目文件/` 文档用 Grep/Glob/Read 核实。两路都查不到才如实说「这个我得查下资料确认,稍回你」。本地文件是保底、并非禁用(之前"禁止读本地"的过激限制已撤销)。
- 知识入库:**优先**把产品手册/项目文档/记忆整理进 gbrain(见 gbrain 自身文档)做主检索源;工作空间 `产品资料/` `项目文件/` 文档树**保留作保底回退**,仍随工作空间维护、不要删。
The skill instructs persistent accumulation of private interaction history and learned context in workspace memory files. Because the skill monitors and auto-replies to workplace conversations, these memory files can contain sensitive personal, operational, or business information and become a high-value local data store.
The migration instructions tell users to populate .env with identifiers and possibly CODEBUDDY_API_KEY for the skill. In the context of an agent that also has file-read capability and broad shell/network access, colocating these secrets in a skill-local file materially raises the chance of credential disclosure or misuse.
# # 然后编辑 ~/.codebuddy/agents/dingtalk-helper.md,把 <BOSS_UID>/<ROS_BASE> 等占位填成你自己的钉钉身份与表结构
# 3) 私密配置(不随包分发,新机自建)
cp ~/.workbuddy/skills/dingtalk-auto-reply/.env.example ~/.workbuddy/skills/dingtalk-auto-reply/.env
# # 编辑 .env 填 BOSS_UID / SELF_OPENDINGTALK_ID / CODEBUDDY_API_KEY(如需)
# 4) dws 入 PATH + 生成本机启动器(幂等,无需重登)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import argparse
_SKILL_DIR = os.path.dirname(os.path.abspath(__file__))
_ENV_PATH = os.path.join(_SKILL_DIR, ".env")
_ENV_EXAMPLE = os.path.join(_SKILL_DIR, ".env.example")
# 复用 runtime.parse_env_text(解析 .env 的唯一实现),需先把 skill 目录加入 sys.path
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import argparse
_SKILL_DIR = os.path.dirname(os.path.abspath(__file__))
_ENV_PATH = os.path.join(_SKILL_DIR, ".env")
_ENV_EXAMPLE = os.path.join(_SKILL_DIR, ".env.example")
# 复用 runtime.parse_env_text(解析 .env 的唯一实现),需先把 skill 目录加入 sys.path
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import argparse
_SKILL_DIR = os.path.dirname(os.path.abspath(__file__))
_ENV_PATH = os.path.join(_SKILL_DIR, ".env")
_ENV_EXAMPLE = os.path.join(_SKILL_DIR, ".env.example")
# 复用 runtime.parse_env_text(解析 .env 的唯一实现),需先把 skill 目录加入 sys.path
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import argparse
_SKILL_DIR = os.path.dirname(os.path.abspath(__file__))
_ENV_PATH = os.path.join(_SKILL_DIR, ".env")
_ENV_EXAMPLE = os.path.join(_SKILL_DIR, ".env.example")
# 复用 runtime.parse_env_text(解析 .env 的唯一实现),需先把 skill 目录加入 sys.path
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import argparse
_SKILL_DIR = os.path.dirname(os.path.abspath(__file__))
_ENV_PATH = os.path.join(_SKILL_DIR, ".env")
_ENV_EXAMPLE = os.path.join(_SKILL_DIR, ".env.example")
# 复用 runtime.parse_env_text(解析 .env 的唯一实现),需先把 skill 目录加入 sys.path
The backup skill materially expands capabilities beyond the declared auto-reply/reminder purpose by authorizing broad workspace querying and direct message sending. This violates least privilege and increases the chance that a user invoking a narrow messaging skill unintentionally grants access to unrelated project, wiki, and workspace data.
The skill proactively instructs the agent to inspect project tables, wiki content, sheets, todos, and calendars without tying that access to the user’s stated request. This broad autonomous data access creates a natural-language exfiltration surface and can expose sensitive business or personal records unrelated to replying to DingTalk messages.
No suspicious patterns detected.