Joplin is a popular open source note-taking app. In versions up to 3.0.14, a trivial parsing quirk let a malicious note turn into remote code execution on the desktop client. The fix is out in 3.0.15. Let’s walk through what went wrong.


What Was the Risk?

Joplin’s HTML parser treated any “<” followed by a non-letter as plain text, not markup. That gap meant you could sneak in an illegal tag sequence, inject an iframe with a javascript: URL, and reach into Joplin’s Node.js context.

  • Any note could carry a payload that becomes active when you view it
  • Payload runs in desktop context, so child_process.execSync is available
  • No UI prompt or warning pops up—you just open the note or paste text, that is it

Affected Versions & Patch

The issue was introduced in the 3.0.13 release and fixed in 3.0.15. Any 3.0.14 or earlier desktop client is vulnerable. Upgrading to 3.0.15 or later closes this hole.

How the PoC Works

Paste this snippet into a note. With the wonders of automatic preview, Joplin will execute a shell command and pop an alert with your /etc/hosts contents. In a real attack you could read any file or run arbitrary commands.

Why It Slipped Through

HTML is flexible, parsing it cleanly is hard.

Key Takeaways

  • Don’t trust edge cases in your HTML parser
  • Any context that mixes user content with privileged APIs needs a strict tag whitelist
  • Please don't allow child_process to be used in your app...

PoC Snippet

<div>
<.a<iframe src=javascript:try{top.alert(parent.parent.require('child_process').execSync('echo\x20$(cat\x20/etc/hosts)'))}catch(e){top.alert(e)} >

That payload abuses the “illegal tag” trick to break out of the note sandbox. If you’re building any editor or renderer that sinks HTML into a native host, make sure your parser rejects non-letter tags.

Wrapping Up

Joplin’s fix arrived quickly and the code is now safe in 3.0.15. This serves as a reminder that small parsing quirks can lead to big trouble when your app bridges web markup and native code.