Vulnerability Report: Unauthenticated Remote Code Execution in Wikimedia's SVGTranslate
System Overview
SVGTranslate, a tool developed by Wikimedia, is designed to convert SVG files into PNG images while allowing for language-based text substitutions within the SVG content. This application uses a PHP backend, with specific functionality managed through the ApiController.php and a service layer implemented in Renderer.php. The source code is available at the SVGTranslate GitHub repository.
- Component Path
- API Controller: /src/Controller/ApiController.php
- Rendering Service: /src/Service/Renderer.php
Vulnerability Description
The application is vulnerable to an unauthenticated remote code execution (RCE) due to improper handling of user input in the language parameter during the PNG generation process. The vulnerability stems from the way shell commands are constructed and executed in the rendering service.
Vulnerability Analysis
Entry Point
The API endpoint defined as:
/** * Serve a PNG rendering of the given SVG in the given language (without any user-provided * translation strings). * * @Route("/api/file/{filename}/{lang}.png", name="api_file", methods="GET") * * @param string $filename * @param string $lang * @return Response */ public function getFile(string $filename, string $lang): Response { $filename = Title::normalize($filename); $content = $this->svgRenderer->render($this->cache->getPath($filename), $lang); return new Response($content, 200, [ 'Content-Type' => 'image/png', 'X-File-Hash' => sha1($content), ]); }
This endpoint processes file names and language parameters to serve PNG files. The lang parameter is passed to the renderer without adequate validation.
Renderer Vulnerability
The Renderer.php service processes the language parameter as part of a shell command:
/** * Render a SVG file to PNG and either save a file or return the image. * @param string $file Full filesystem path to the SVG file to render. * @param string $lang Code of the language in which to render the image. * @param string $outFile Full filesystem path to the file to write the PNG to. * @throws ProcessFailedException If the PNG conversion failed. * @return string The PNG image contents, or nothing if an $outFile was provided. */ public function render(string $file, string $lang, ?string $outFile = null) : string { $command = $this->rsvgCommand.' "$SVG"'; if ('fallback' !== $lang) { $command .= " --accept-language=$lang"; } if ($outFile) { $command .= ' > "$PNG"'; } $process = Process::fromShellCommandline($command); $process->mustRun(null, ['SVG' => $file, 'PNG' => $outFile]); return $process->getOutput(); }
The vulnerability is in the concatenation of the $lang variable into the shell command without proper sanitization. This allows an attacker to inject additional shell commands.
Proof of Concept
Using the following request, an attacker can execute arbitrary commands:
GET /api/file/SI_base_unit1.svg/fr;id;.png HTTP/2 Host: svgtranslate.toolforge.org
This results in unauthorized command execution, as demonstrated by the server response showing system user information.
Mitigation Recommendations
- Input Validation: Implement strict validation for all input parameters, especially those being incorporated into command line operations.
- Secure Command Execution: Use array parameters for command execution to ensure separation between commands and arguments, preventing injection.
- Security Audit and Testing: Conduct a thorough security review and penetration testing to identify and fix potential vulnerabilities.
NOTE
In this report, the vulnerability was directly tested on the Wikimedia instance, demonstrating the issue without setting up a separate testing environment. This was done to quickly verify the clear and evident potential for exploitation as indicated by the code analysis. It should be noted that no harmful actions were undertaken during this testing process.