95 lines · 3.9 KB
import { test } from "node:test";
import assert from "node:assert/strict";
import { escapeMarkdown, htmlToText } from "../src/adapters/discord/html-to-text.ts";

// Everything an email carries is attacker-controlled: anyone who learns an
// address can send to it, and Discord renders markdown in bot messages. The
// headline risk is a masked link, `[label](url)`, arriving as a clickable
// link whose visible text lies about where it goes.
test("markdown escaping", async (t) => {
  await t.test("defuses a masked link in plain text", () => {
    const out = escapeMarkdown("Verify at [www.yourbank.com](https://evil.example/steal)");
    assert.match(out, /\\\[www\.yourbank\.com\\\]/);
  });

  await t.test("defuses a masked link written into an anchor's own label", () => {
    const out = htmlToText('<a href="https://real.example">[www.yourbank.com](https://evil.example)</a>');
    assert.match(out, /\\\[/);
    assert.ok(out.includes("(<https://real.example>)"), out);
  });

  await t.test("defuses brackets smuggled in as HTML entities", () => {
    // Entity decoding has to happen before escaping, or &#91; slips through
    // as a live bracket.
    assert.ok(htmlToText("<p>&#91;label&#93;(https://evil.example)</p>").includes("\\[label\\]"));
  });

  await t.test("escapes formatting characters", () => {
    assert.doesNotMatch(escapeMarkdown("**b** _i_ `c` ~s~ ||x||"), /(?<!\\)[*_`~|]/);
  });

  await t.test("a backslash cannot be used to undo the escaping", () => {
    assert.ok(escapeMarkdown("\\[x](y)").startsWith("\\\\\\["));
  });

  await t.test("leaves ordinary punctuation readable", () => {
    // Escaping these too would be correct but makes normal prose unreadable,
    // and they're cosmetic at worst: no link can be forged with them.
    const prose = "Order #123 (shipped) - 50% off > see details";
    assert.equal(escapeMarkdown(prose), prose);
  });