Tagify XSS

CVE-2022-25854: Stored XSS in @yaireo/tagify npm module

Preface

Due to the russian war on Ukraine, we are much less active on this blog and social media. However, some events make us hit the dust off the keyboard and share some information. For instance, a vulnerability is worth a CVE. We found this one in February 2022, and a few others are under review. Meanwhile, all BSG team members are safe, and we stay operational.

Introduction

Tagify is a tags input component for React, Vue, and Angular that can also be used as a standalone library in pure JavaScript. It transforms an input field or a textarea into a Tags component.

Tagify example.
A Tagify example.

Tagify resources and project homepage:

Summary

A Cross-site Scripting (XSS) issue was discovered in @yaireo/tagify versions before 4.9.8 (CVE-2022-25854). An attacker could exploit it by storing persistent scripts, which would lead to arbitrary code execution when visiting an affected page.

Impact

Tagify is a quite popular JavaScript library: there are 38 000 weekly downloads on npm and 24 packages depending on @yaireo/tagify.

Technical Summary

While testing custom inputs functionality on a website, we observed that the “tags” parameter was not sanitized against cross-site scripting attacks when loading the data via the user’s profile page.

Deep dive into the code base showed that the bug is in Tagify’s template wrapper, leading to an XSS vulnerability, making applications that use tagify.js or react.tagify vulnerable as well.

XSS example.
The XSS example.

Affected Code

https://github.com/yairEO/tagify/blob/f74c1570496f76ba798062680529efea7b5b1332/src/parts/templates.js#L13

data-placeholder="${_s.placeholder || '​'}"
aria-placeholder="${_s.placeholder || ''}"

Example on Codesandbox: https://codesandbox.io/s/tagify-react-wrapper-forked-lgs3er?file=/src/CrazyTags.jsx:392-443

Tagify’s API does not provide any documented options to add onhover, onclick, etc., handlers using the placeholder prop. There is no way to add the handlers using any other props described in the TagifyWrapper.propTypes object, except placeholder. It is undocumented, unintended, and unexpected behavior.

Pull request

https://github.com/yairEO/tagify/commit/198c0451fad188390390395ccfc84ab371def4c7

Disclosure Timeline

  • 2022-02-11 Bug discovered.
  • 2022-02-15 Found the source of the bug.
  • 2022-02-15 Created PoC.
  • 2022-02-16 Disclosure to vendor.
  • 2022-02-16 Pull Request with the fix was sent to the vendor.
  • 2022-02-17 Vendor informed us that it would be fixed with the following product version (v4.9.8).
  • 2022-02-17 Vendor published a fixed product version (v4.9.8).

Proof of Concept

  1. Open the following forked Tagify’s React Wrapper demo.
  2. Notice line #17, where a customUserInput variable is declared. This variable mocks data that came from an API or an input.
  3. On line #23, we use the customUserInput variable to customize tags.
  4. Open the Tags tab once the demo app is rendered and hover on the first input. It will fire the XSS.
XSS Proof of Concept
The XSS Proof of Concept.

Solution

As of the date of this publication, all versions above 4.9.8 are safe to use.

Credits

The BSG team: Roman Rott, Serhii Korolenko, Ihor Bliumental, and Maksym Khramov.

Leave a Comment