Back to Blog
high SEVERITY4 min read

linkify-it 5.0.1 mailto: Link Parsing Causes DoS

linkify-it versions up to 5.0.1 can be forced into excessive processing time when autolinking a specially crafted mailto: link, allowing a remote attacker to degrade or stall the parsing thread. Upgrading to linkify-it 5.0.2 closes the issue; any application that runs linkify-it (directly or via markdown-it) against untrusted text should update immediately.

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published September 30, 2026•Reviewed September 30, 2026

Answer Summary

linkify-it versions up to and including 5.0.1 are affected. An attacker who can supply text that gets autolinked — for example a comment, markdown document, or chat message — can craft a mailto: link that causes the library's link-matching logic to consume disproportionate CPU time, resulting in denial of service for the parsing process. The fix, shipped in linkify-it 5.0.2, corrects the mailto: link matching behavior so crafted input no longer triggers pathological processing. The associated CWE has not been assigned by the advisory.

Vulnerability at a Glance

cweunknown
fixUpgrade linkify-it to 5.0.2, which corrects the mailto: link matching logic
riskA single malicious mailto: link can stall or exhaust CPU on the thread running linkify-it, blocking autolinking (and anything sharing that event loop, e.g. Node.js request handling)
languageJavaScript
root causelinkify-it's mailto: schema matcher in 5.0.1 processes crafted local-part/domain combinations inefficiently, leading to disproportionate scan time
vulnerabilityDenial of Service (uncontrolled resource consumption) via crafted mailto: link

Introduction

linkify-it is the autolinking engine behind popular markdown renderers like markdown-it — it scans plain text for things that look like URLs, emails, or mailto: addresses and turns them into clickable links. Because it runs on untrusted input (comments, markdown documents, chat messages, README files rendered on the fly), any inefficiency in its matching logic becomes a direct denial-of-service vector against whatever process is doing the rendering.

CVE-2026-59887 affects linkify-it 5.0.1: when the library's mailto: link matcher is handed a specially crafted address, it can burn a disproportionate amount of CPU time relative to the size of the input before it decides whether the text is or isn't a valid mailto link. An attacker doesn't need to control an entire document — a single crafted mailto: substring embedded in an otherwise ordinary paragraph is enough to trigger the slow path.

Affected Versions

Affected 5.0.1
Fixed in 5.0.2
Ecosystem npm
CVE / GHSA CVE-2026-59887 / not assigned
CWE unknown

The Vulnerability Explained

linkify-it maintains a set of schema matchers — one for http:, one for mailto:, and so on — that are tried against every position in the text being scanned. The mailto: matcher has to validate the shape of an email address (local-part, @, domain) inline, without the benefit of a full email-parsing grammar, because it's operating character-by-character over arbitrary text rather than a pre-tokenized address field.

In 5.0.1, that inline validation logic could be pushed into a pathological processing path by a carefully constructed local-part/domain combination in a mailto: link. Instead of failing fast on invalid or edge-case input, the matcher spends far more time than the input length would justify — the hallmark of a resource-exhaustion bug rather than a memory-safety one.

Attack scenario: Consider a service that renders user-submitted markdown with markdown-it and has linkify: true enabled (the common configuration for "GitHub-flavored" rendering). An attacker submits a comment or issue body containing a normal-looking paragraph with one crafted mailto: link buried in it. When the server calls into markdown-it's renderer — which delegates to linkify.match() under the hood — the request thread stalls processing that single document. Repeat the submission a handful of times concurrently, and the render workers (or the whole Node.js event loop, if rendering happens synchronously on it) back up, degrading or halting the service for all users — a classic high-severity availability issue with a very low bar to exploit.

The trivy scan that flagged this in the dependency tree couldn't confirm reachability from source, but any code path that feeds attacker-influenced text into linkify-it's matching functions — directly or through markdown-it — is exposed.

The Fix

The remediation here is a dependency version bump, not a source-code patch in this repository: linkify-it is upgraded from 5.0.1 to 5.0.2 in the manifest and lockfile.

-    "linkify-it": "5.0.1"
+    "linkify-it": "5.0.2"

Upstream, 5.0.2 corrects the mailto: matcher so that crafted local-part/domain input no longer forces the disproportionate scan behavior — the matcher now rejects malformed or adversarial mailto candidates without the excessive processing cost. Because the fix lives entirely inside linkify-it, no application code needs to change; consumers only need to pull in the patched dependency.

It's worth noting that the diff for this change is otherwise dominated by unrelated lockfile bookkeeping — moving a typedoc-material-theme entry from dependencies to devDependencies and marking a few Shiki-related packages as dev — none of which affects runtime behavior. The security-relevant change is exclusively the linkify-it version bump.

Key Takeaways

  • If your app renders user-supplied markdown with linkify enabled, treat linkify-it as directly reachable by attacker input, not as an incidental transitive dependency.
  • A DoS in a link-matching library doesn't need a huge payload — one crafted mailto: substring inside a normal document is enough.
  • Pin and monitor linkify-it versions the same way you would any parser that runs against untrusted text; 5.0.1 → 5.0.2 is a drop-in, no-API-change upgrade.
  • Rendering markdown synchronously on a shared event loop (e.g., Node.js) turns a single slow parse into a service-wide stall — consider isolating rendering for untrusted content regardless of this specific fix.

How Orbis AppSec Detected This

  • Source: text passed into linkify.match() / linkify.test() — typically user-submitted markdown, comments, or chat content routed through markdown-it's linkify option.
  • Sink: linkify-it's internal mailto: schema matcher, invoked automatically during autolink scanning.
  • Missing control: no bound on the processing cost of validating a crafted mailto: local-part/domain combination before version 5.0.2.
  • CWE: unknown (not assigned in the advisory).
  • Fix: Upgrade the linkify-it dependency from 5.0.1 to 5.0.2, which patches the mailto: matching logic.

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

CVE-2026-59887 is a reminder that autolinking libraries sit directly in the path of untrusted text, and a single inefficient matcher — here, the mailto: handler in linkify-it 5.0.1 — is enough to turn ordinary content rendering into a denial-of-service vector. The fix is a one-line dependency bump to 5.0.2, but the impact scales with how much of your rendering pipeline touches attacker-controlled text, so it's worth verifying the upgrade landed anywhere linkify-it or markdown-it's linkify option is in use.

Prevention and further reading

Frequently Asked Questions

Does upgrading linkify-it from 5.0.1 to 5.0.2 change its public autolinking API?

No. The fix is contained to the mailto: link matching behavior; `linkify.match()`, `linkify.test()`, and schema registration work exactly as before.

Am I exposed if my project only uses linkify-it indirectly through markdown-it?

Yes, if the markdown-it linkify option is enabled and untrusted text is rendered, since markdown-it delegates autolinking to linkify-it's 5.0.1 mailto: matcher.

Does this vulnerability require the attacker to control the whole document, or just a substring?

Just a substring — a single crafted mailto: link embedded anywhere in otherwise normal text is sufficient to trigger the excessive processing.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #33

Related Articles

critical

Lampa Desktop Auto-Update Heuristic Bypass: Execution of Unverified

Lampa Desktop's auto-update mechanism downloaded JavaScript and CSS from `raw.githubusercontent.com` using only heuristic validation—file size thresholds and string pattern matching—that attackers could trivially satisfy. The fix introduces cryptographic integrity verification by cross-referencing Git blob hashes from the GitHub Contents API, ensuring downloaded code matches the repository's authoritative state before execution.

high

adm-zip 0.6.0 Preserves SUID Bits From ZIPs: CVE-2026-102282

The `adm-zip` dependency resolved to 0.6.0 in this project's dependency tree, a version affected by CVE-2026-102282: during extraction it applies the Unix permission bits stored in each ZIP entry's external file attributes verbatim, including the setuid (`04000`), setgid (`02000`), and sticky bits. An attacker who controls an archive passed to `extractAllTo()` or `extractEntryTo()` can therefore have the extractor create a setuid binary owned by whatever user the extraction process runs as. The

high

requestInput() Type Confusion: NaN and Object Bypass in JavaScript

The `requestInput()` utility function lacked validation on its `type` parameter and failed to handle `NaN` results from float conversions, creating a type confusion weakness. An attacker could supply malformed inputs that propagate unhandled `NaN` values or unexpected object types through the type system. The fix adds explicit guards against `NaN` type parameters and rejects non-primitive type values.

critical

No Rate Limit on /api/uploads/presign Enables DoS

The `/api/uploads/presign` endpoint accepted unlimited concurrent requests to generate storage presigned URLs, giving an attacker a free lever to exhaust storage-provider quotas and server resources. The fix adds an `express-rate-limit` middleware capping each client to 30 requests per minute on that route.

high

CVE-2026-54673: builder-util-runtime Leaks Auth Headers on Redirect

electron-updater and electron-builder rely on builder-util-runtime to fetch update manifests and artifacts over HTTP. A flaw in that shared HTTP executor allowed credential headers attached to the original update-feed request to be re-sent after a redirect, exposing them to any host the redirect pointed to. The project fixes this by upgrading builder-util-runtime to 9.7.0 and collapsing a duplicate, older copy of the package that electron-updater had pinned on its own.

high

image-size 1.2.1 DoS: Zero-Valued Dimensions in Image Buffer Parser

A high-severity denial-of-service vulnerability in image-size 1.2.1 allows attackers to crash Node.js services using malicious image buffers with zero-valued dimensions. The fix removes the vulnerable `queue` dependency and tightens dimension validation in version 2.0.3.