Skip to content

Slack: inbound bold conversion doubles literal asterisks in prose and inside inline code #954

Description

@szachariah-tl

Bug Description

slackMrkdwnToMarkdown converts Slack bold to markdown bold with

markdown.replace(/(?<![_*\\])\*([^*\n]+)\*(?![_*])/g, "**$1**");

The pattern matches any two asterisks on the same line, whatever surrounds them. A message that uses * as a multiplication sign or a wildcard has each matched asterisk doubled. The rule also runs over inline code spans, so the contents of `…` are changed.

Slack's own renderer does not show these messages as bold: its mrkdwn bold needs a non-space character directly inside each marker.

Steps to Reproduce

  1. In Slack, send the bot cost is 2 * 3 seats and 4 * 5 licenses, or a message with an asterisk inside inline code such as run `rm -rf *` then 5 * 3.
  2. Read message.text and stringifyMarkdown(message.formatted) in the handler, or run the code sample below, which calls the same converter the adapter uses.

Expected Behavior

Both messages come through with their asterisks unchanged and no strong node. this is *bold* text still converts to **bold**.

Actual Behavior

Input (event.text) message.text stringifyMarkdown
cost is 2 * 3 seats and 4 * 5 licenses cost is 2 ** 3 seats and 4 ** 5 licenses cost is 2 \*\* 3 seats and 4 \*\* 5 licenses
run `rm -rf *` then 5 * 3 run rm -rf ** then 5 ** 3 run `rm -rf **` then 5 \*\* 3

In the second row the match starts at the asterisk inside the code span and ends at the one outside it, so the code span's content changes from rm -rf * to rm -rf **.

Code Sample

import { SlackFormatConverter } from "@chat-adapter/slack";
import { stringifyMarkdown, toPlainText } from "chat";

const converter = new SlackFormatConverter();
for (const input of ["cost is 2 * 3 seats and 4 * 5 licenses", "run `rm -rf *` then 5 * 3"]) {
  const ast = converter.toAst(input);
  console.log(toPlainText(ast));
  console.log(stringifyMarkdown(ast));
}

Chat SDK Version

4.30.0

Node.js Version

22.21.1

Platform Adapter

Microsoft Teams, Slack

Operating System

Linux

Additional Context

Possible approaches.

  • Require a non-space character after the opening asterisk and before the closing one: /(?<![_*\\])\*(\S(?:[^*\n]*\S)?)\*(?![_*])/g. On the inputs above it leaves both messages unchanged and still converts *bold*, *a* and *b c*, and *x*. The strikethrough rule (~…~) has the same shape and would take the same change.
  • Skip inline code spans. 4.40.0 already splits the input on code fences (convertMrkdwnWithCodeFences) so fenced code is not rewritten; inline `…` spans still are.
  • When the event carries rich_text blocks, bold is unambiguous there (style.bold on the text element), so reading formatting from blocks would avoid the regex for user-typed messages.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions