Skill flagged — suspicious patterns detected

ClawHub Security flagged this skill as suspicious. Review the scan results before using.

Bilibili Messager

v1.4.1

通过浏览器自动化发送 B 站私信、回复消息、读私信、看聊天记录。 Send Bilibili DMs, reply to messages, read chat history, and browse conversations via browser automation.

0· 802·3 current·3 all-time
byMorois@moroiser
Security Scan
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Suspicious
medium confidence
Purpose & Capability
The SKILL.md describes browser automation for reading, replying, and sending Bilibili private messages, and the instructions show exactly that: opening the Bilibili message page, locating conversations, reading DOM, writing message content, and clicking send. Required capabilities are coherent with the stated purpose.
Instruction Scope
Instructions operate directly on the page DOM (expected) and enforce a two-step user confirmation before send operations (good). However the skill instructs taking full page snapshots for diagnostics and uses the entire browser profile ('openclaw'), which can capture and expose unrelated page content, cookies, or other sites' data. The DOM-extraction scripts are specific to class-name patterns (fine), but some selectors/regexes appear brittle (e.g., regex requiring a trailing space) — a robustness/bug issue, not necessarily malicious.
Install Mechanism
No install spec and no code files beyond SKILL.md — low installation risk. The skill is instruction-only and will not write new binaries or install packages.
Credentials
The skill requests no environment variables or credentials (good). Practically, it requires using a logged-in browser profile (named 'openclaw') to perform actions; that implicitly grants access to session cookies and any data available in that profile. This is proportional to the purpose but carries privacy risk and should be acknowledged by the user.
Persistence & Privilege
always is false and the skill is not force-included. The skill does not request persistent elevated privileges or modifications to other skills or system settings.
What to consider before installing
This skill appears to do what it says (automate Bilibili DMs) and includes safe-seeming confirmation steps before sending messages. Before installing or using it, consider: - The skill expects to use a logged-in browser profile (the 'openclaw' profile). Using an existing profile gives the agent access to session cookies and any pages open in that profile; if you are uncomfortable with that, use a dedicated temporary profile or a throwaway account. - The skill may take full page DOM snapshots for diagnostics. Those snapshots can include unrelated sensitive information (other sites, embedded tokens, or account details). Only allow snapshots when necessary and review what will be captured. - The SKILL.md is instruction-only from an unknown source (no homepage). The owner and version metadata show a minor mismatch — verify you trust the publisher before enabling automated sends. - Confirm that the agent always asks for the explicit user confirmation (the SKILL.md requires it); do not allow the skill to send messages autonomously without that explicit confirmation. If you need stronger guarantees, request a version of this skill that runs in an isolated browser context or that provides explicit previews of any snapshots before they are transmitted/stored.

Like a lobster shell, security has layers — review code before you run it.

latestvk972tvqt7zsy76y6554fxm27cx84pyyc
802downloads
0stars
10versions
Updated 4h ago
v1.4.1
MIT-0

Bilibili Private Messaging | B站私信自动化

模式 | Mode

读取本 SKILL.md 后,先确认当前任务属于哪种模式,再跳转对应章节执行。

模式说明
send发送新私信(必须两步验证)
reply回复现有会话中的消息(必须两步验证)
read读取聊天记录(只读,不写入任何内容)

通用原则 | General Principles

  1. Browser profile:使用 openclaw profile(已登录 Bilibili)
  2. 两步验证:发送类操作(send / reply)必须两步验证,不可跳过
  3. 只读优先:读取聊天记录使用 read 模式,不执行任何写入操作
  4. 发送前确认:执行任何对外发送前,必须先向用户确认目标账号和消息内容

发送私信 | Mode: Send

步骤 1:打开私信页并确认登录

browser action=open targetUrl=https://message.bilibili.com/#/whisper

检查页面是否跳转到登录页。若跳转到登录页,停下来让用户完成登录。

步骤 2:找到目标会话

在左侧会话列表中找到目标联系人。可以通过文字搜索或滚动列表。

  • 使用 browser action=act evaluate 配合 DOM 查询找到目标会话
  • 找到后点击进入会话

步骤 3:两步验证(强制,必须执行)

第一步(AI 内部执行,不输出给用户)

  • 确认已正确进入目标会话(检查 URL 包含 mid 参数或页面标题显示对方名字)
  • 确认消息内容已准备完毕
  • 检查消息长度(不超过 500 字)

第二步(输出给用户,等待明确确认)

向用户汇报以下全部内容,确认前不得写入或发送

汇报项内容
目标账号会话对方的名字
消息内容将要发送的完整内容
字数是否在 500 字以内

确认标志:用户明确回复「好」「确认」「发」「发吧」「发送」等。

步骤 4:写入消息

使用 innerText 方式写入(经验证有效):

() => {
  var editor = document.querySelector('.content-input, [contenteditable="true"]');
  if (!editor) return 'editor not found';
  editor.focus();
  editor.innerText = '消息内容';
  editor.dispatchEvent(new Event('input', {bubbles: true}));
  return 'typed';
}

步骤 5:点击发送按钮

() => {
  var btns = document.querySelectorAll('button, [class*="btn"]');
  for (var btn of btns) {
    if ((btn.textContent || '').includes('发送')) {
      btn.click();
      return 'sent';
    }
  }
  return 'send button not found';
}

注意

  • navigator.clipboard.writeText() + execCommand('paste') — 对B站无效
  • ❌ Enter 键发送 — 对B站无效
  • ✅ 直接设置 innerText + 触发 input 事件 — 成功

步骤 6:验证发送结果

  • 发送成功后,消息会出现在聊天窗口中
  • 侧边栏会话列表的预览也会更新

回复消息 | Mode: Reply

回复与发送流程基本相同,区别在于:

  1. 先用 read 模式确认要回复的消息内容
  2. 在对应会话中打开对话
  3. 后续步骤同发送流程(步骤 3 两步验证 → 步骤 4 写入 → 步骤 5 发送)

读取聊天记录 | Mode: Read

步骤 1:打开私信页

browser action=open targetUrl=https://message.bilibili.com/#/whisper

步骤 2:找到并打开目标会话

在左侧会话列表中找到目标联系人,点击进入。

步骤 3:提取聊天记录

⚠️ 核心原则:判断发送方归属,100% 依赖 DOM class 名称,不靠语义内容猜测。

发送方归属规则(重要,必读)

B站消息 DOM 结构说明

B站私信页面上,每条消息是一个 HTML 元素,该元素的 class 属性包含判断归属的关键信息。

class 名称的格式一(我发的消息):

class="_Msg_o7f0t_1 _MsgIsMe_o7f0t_9"
  • _Msg_o7f0t_1:消息容器(固定前缀 _Msg_ + 会话ID o7f0t + 数字 1
  • _MsgIsMe_o7f0t_9附加标记,表示"这条消息是当前登录用户发的"

class 名称的格式二(对方发的消息):

class="_Msg_o7f0t_1"
  • 只有 _Msg_ 开头的容器 class,没有 _MsgIsMe_ 标记
  • 表示这条消息是对方发的

关于会话ID(上面例子里的 o7f0t):

  • 会话ID是B站为每个私信会话分配的随机字符串,不同会话ID不同
  • 代码中用 [a-z0-9]+ 匹配(ID只包含小写字母和数字)
判断规则(4步)
  1. 找到所有顶级消息容器

    • 用 CSS 选择器 [class*="_Msg_"] 找到所有包含 _Msg_ 的元素
    • 再用正则 _Msg_[a-z0-9]+_\d+ 过滤,只保留顶级容器
      • 匹配成功举例:_Msg_o7f0t_1_Msg_abc123_42_Msg_x_99
  2. 判断发送方归属

    • 如果该元素的 class 里包含 _MsgIsMe_,则这是一条我发的消息(Morois / 当前登录用户)
    • 如果该元素的 class 里不包含 _MsgIsMe_,则这是一条对方发的消息
  3. ❌ 禁止用左右位置判断

    • B站的消息布局可能产生误导——例如对方发的消息有时也会渲染在右侧
    • 永远不要用"左侧/右侧"或"left/right"作为判断依据
    • 只用 _MsgIsMe_ 有没有出现来判断
具体 class 名称示例
class 名称含义
_Msg_o7f0t_1消息容器,会话ID是 o7f0t,序号1
_Msg_o7f0t_1 _MsgIsMe_o7f0t_9我发的消息(morois发的),有 _MsgIsMe_ 标记
_Msg_abc123_42消息容器,会话ID是 abc123,序号42,对方发的
_Msg_x_7消息容器,会话ID是 x,序号7,对方发的
_MsgIsMe_x_15我发的消息(morois发的),会话ID是 x,序号15
提取脚本(完整示例)
() => {
  const containers = Array.from(document.querySelectorAll('[class*="_Msg_"]'))
    .filter(el => el.className.match(/_Msg_[a-z0-9]+_\d+ /));

  const results = [];
  for (const el of containers) {
    const cls = el.className + '';

    // 关键判断:有 _MsgIsMe_ → 我发的;没有 → 对方发的
    const isMe = cls.includes('_MsgIsMe_');
    const sender = isMe ? '【我方/Morois】' : '【对方】';

    // 提取时间
    const timeEl = el.querySelector('[class*="_Msg__Time_"]');
    const time = timeEl ? timeEl.textContent.trim() : '';

    // 提取消息内容(可能有多个 Content class,取非重复内容)
    const contentEls = el.querySelectorAll('[class*="_Msg__Content_"]');
    const texts = [];
    for (const c of contentEls) {
      const t = (c.textContent || '').trim().replace(/\s+/g, ' ');
      // 排除时间格式的内容(如"2026年3月28日 18:00")
      if (t && !t.match(/^\d{4}年/)) texts.push(t.slice(0, 200));
    }
    const uniqueTexts = [...new Set(texts)];
    const text = uniqueTexts.join(' | ');

    if (text) results.push({ sender, time, text });
  }
  return results;
}
注意事项
  • 保留所有消息类型:文本、视频分享、图片、卡片等,不要因为不是纯文本就丢弃
  • 结合时间戳重建时间线
  • DOM 结构变化时,参考常见问题 → 页面布局变了

常见问题

找不到编辑器

B站私信页面的编辑器可能出现在不同位置。尝试:

() => {
  const selectors = [
    '.content-input',
    '[contenteditable="true"]',
    '[class*="editor"]',
    '[class*="input"]'
  ];
  for (const sel of selectors) {
    const el = document.querySelector(sel);
    if (el) return sel + ' found: ' + el.className;
  }
  return 'no editor found';
}

找不到发送按钮

发送按钮可能没有稳定的 class 或 ref。查找包含"发送"文字的按钮:

() => {
  const btns = document.querySelectorAll('button, [class*="btn"], [class*="send"]');
  for (const btn of btns) {
    if ((btn.textContent || '').includes('发送')) {
      return 'found: ' + btn.className;
    }
  }
  return 'send button not found';
}

页面布局变了(DOM 结构诊断)

如果脚本返回空结果或找不到元素,按以下顺序诊断:

  1. 先快照:用 browser action=snapshot 获取当前页面完整 DOM
  2. 找消息容器:在快照中搜索 _Msg_message
  3. 找编辑器:搜索 contenteditableinputeditor
  4. 找发送按钮:搜索 发送 文字或 button
  5. 根据诊断结果:用实际找到的 class/name 重写选择器

诊断脚本:

() => {
  return {
    msgs: Array.from(document.querySelectorAll('[class*="Msg"]')).slice(0,3).map(el=>el.className),
    editor: document.querySelector('[contenteditable="true"]') ? 'found' : 'not found',
    btns: Array.from(document.querySelectorAll('button')).map(b=>b.textContent.trim()).filter(t=>t)
  };
}

限制与注意事项

  • 消息长度限制 500 字,超长需分段发送
  • 避免高频发送
  • 读取记录时优先保证归属和类型正确,再追求历史深度
  • 发送前必须用户明确确认目标账号和消息内容

Comments

Loading comments...