> Summary: In early 2024, a major security flaw (CVE-2024-27285) was discovered in YARD, the popular Ruby documentation generator. If you expose your YARD-generated docs (especially frames.html) on a server, attackers might run malicious JavaScript in your users’ browsers. This post breaks down how the bug happens, shows a proof-of-concept exploit, and explains how to fix it.

What is YARD?

YARD is one of the most used tools in the Ruby ecosystem for building documentation from your code comments. It auto-generates HTML files—including a useful frames view (frames.html) for browsing documentation quickly.

The Bug: XSS in frames.html

The culprit is a Cross-Site Scripting (XSS) vulnerability in the frames.html file YARD creates. Basically, untrusted user input can end up in a place in frames.html where JavaScript runs unchecked. This happens in the JavaScript template powered by the frames.erb view.

How It Happens

Here’s a distilled example. Inside YARD’s frames.erb, there’s JavaScript code that trusts variables it shouldn’t trust:

<script type="text/javascript">
  // ...some other JS code...
  var search = window.location.search;
  // more code that manipulates "search" – potentially inserting it unsafely
  // Example:
  document.getElementById('search-bar').value = search.replace('?q=', '');
</script>

If a user visits something like

https://docs.yoursite.com/frames.html?q="><script>alert('hacked!')</script>;

and if the value for the search bar isn’t properly sanitized, the attacker’s code runs right in the browser.

Proof-of-Concept Exploit

Let’s see a real example using YARD-generated documentation.

Suppose YARD .9.35 or older generates your documentation. Your server hosts /docs/frames.html.

Attack URL

https://docs.example.com/frames.html?"><svg/onload=alert('XSS')>;

If vulnerable, when you open this link, a popup says “XSS”—meaning your site can run attacker’s code!

Vulnerable code snippet (simplified for clarity)

// frames.erb inside a JS block
var search = window.location.search;
document.getElementById('search-bar').value = search.replace('?q=', ''); // Not sanitized!

The injected string appears in the DOM or scripting context without being escaped.

Technical Details

- Affected File: templates/default/frames.erb (in YARD source)

Affected YARD Versions: ≤ .9.35

- Fixed In: .9.36 (Release notes here)
- Exploitability: Anyone who can trick a user into clicking a crafted link, or browsing to public docs.

How the Patch Works

The fix escapes or sanitizes any dynamic input (e.g. using Ruby’s h() or CGI.escapeHTML) before using it in the JavaScript, or simply refactors the script to never insert raw query params directly into the HTML.

Example of a fixed pattern

var search = window.location.search;
// Use a function to strip everything but safe characters
var safeSearch = search.replace(/[^a-zA-Z-9 ]/g, '');
document.getElementById('search-bar').value = safeSearch;

Old generated .html files remain unsafe until replaced.

3. Sanitize external/public-facing documentation

Additional Resources

- Original CVE: CVE-2024-27285
- YARD GitHub - Security advisory
- Patch Commit
- OWASP XSS Overview

Final Thoughts

Exposing documentation might seem harmless, but even docs need security. This YARD bug is a textbook example of why you should *never blindly trust user input—even in tools you only use for code documentation*. Upgrade now and review your deployment practices!

Timeline

Published on: 02/28/2024 20:15:41 UTC
Last modified on: 03/06/2024 23:15:07 UTC