Coordinated Disclosure Timeline
- 2024-06-05: Vulnerability was reported via GitHub’s private vulnerability reporting feature.
- 2024-07-19: Security advisory was published by the Haven project.
Summary
A command injection vulnerability was found in the IndieAuth functionality of the Ruby on Rails based Haven blog web application. The affected functionality requires authentication, but an attacker can craft a link that they can pass to a logged in administrator of the blog software. This leads to the immediate execution of the provided commands when the link is accessed by the authenticated administrator.
Project
Haven
Tested Version
Details
Remote code execution in IndieAuthClient (GHSL-2024-093
)
A command injection vulnerability was found in the IndieAuth functionality of the Ruby on Rails based Haven blog web application. An unauthenticated attacker could provide a specially crafted URL to an authenticated administrator of a Haven instance. If such a URL contains the query parameter client_id
with a value that starts with the pipe symbol (|
) then the following commands are executed as shell commands on the server running Haven. This is due to the used URI.open
behaving similar to Ruby’s Kernel.open
in addition to being able to open remote URLs.
The entry point for a malicious client_id
value is the authorization
method on the IndieauthController
class:
def authorization
@auth_request = IndieAuthRequestObj.new(params)
@client = IndieAuthClient.new(@auth_request.client_id)
In this method a new IndieAuthRequestObj
object is created, where checks are made if all required query parameters have been passed in (client_id
, redirect_uri
, state
, code_challenge
and code_challenge_method
). The client_id
of this IndieAuthRequestObj
is then passed to initialize
of IndieAuthClient
, which then calls the dangerous URI.open
sink with it:
def initialize(client_id)
@client_id = client_id
[..]
if should_fetch?
begin
URI.open(client_id) do |f|
Although the method should_check?
calls a method called parse_hostname
an attacker can get through this check by creating a client_id
with a hostname with scheme after the shell command (e.g. | touch pwned.txt | https://example.org
).
This vulnerability was discovered with the help of CodeQL’s Use of Kernel.open, IO.read or similar sinks with user-controlled input query.
Proof of Concept
If an authenticated Haven administrator user visits a URL such as:
https://<haven-host>/indieauth/authorization?response_type=code&client_id=|%20touch%20pwned.txt%20|%20https:%2f%2fexample.org&redirect_uri=any&state=any&code_challenge=12345678&code_challenge_method=S256
The command touch pwned.txt
is executed, which leads to the creation of the file pwned.txt
. Since the route /indieauth/authorization
can be accessed via GET request an attacker could send such an URL to an administrator for a Haven blog (or redirect them to it; assuming the internal or external haven-host
is known.)
Impact
This issue may lead to Remote Code Execution (RCE).
Resources
CVE
- CVE-2024-39906
Credit
This issue was discovered and reported by GHSL team member @p- (Peter Stöckli).
Contact
You can contact the GHSL team at securitylab@github.com
, please include a reference to GHSL-2024-093
in any communication regarding this issue.