Fedora Account System
Red Hat Associate
Red Hat Customer
AI_ONLY_REPORT package: flatpak-builder-1.4.4-1.el10 ------ Summary: Local File Exfiltration via `file://` URLs in Manifest Source Downloads: attacker-controlled `file` and `archive` manifest sources can use `file://` URLs to read host files and move their contents into build inputs and artifacts, including when `--sandbox` is used. Requirements to exploit: An attacker must supply or influence a manifest that uses a `type: file` or `type: archive` `url:` source with a `file://` URI, and a user or CI worker must run `flatpak-builder` against that manifest on a host where the targeted file is readable. A correct checksum is required for successful ingestion, but the implementation discloses the measured checksum on mismatch, which makes subsequent successful runs practical when build output is visible. Component affected: `flatpak-builder-1.4.4-1.el10`, primarily `src/builder-context.c` (`builder_context_download_uri`), reached from `src/builder-source-file.c` and `src/builder-source-archive.c`; related download handling is in `src/builder-utils.c` and `src/builder-flatpak-utils.c`. Version affected: `flatpak-builder-1.4.4-1.el10` Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not notified. CVSS: CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N - 6.1 (MEDIUM) AV:L - Exploitation occurs in a local build or local CI execution context. AC:L - The manifest directly controls the URL, and the checksum can be learned from the mismatch error before rerunning. PR:N - The attacker does not need prior privileges on the build host. UI:R - A user or CI job must run `flatpak-builder` on the malicious manifest. S:U - The impact remains within the flatpak-builder/build-output security scope. C:H - Readable host files can be disclosed by copying them into downloaded sources or resulting artifacts. I:L - Build inputs and outputs can be altered to include attacker-selected host file contents. A:N - No direct availability impact was demonstrated. Impact: Moderate. The flaw can expose host-readable files and influence build outputs, but exploitation depends on a user or CI system processing an attacker-controlled manifest. That makes it less readily exploitable than Red Hat's Important or Critical classes, even though the confidentiality impact can be high once triggered. Embargo: no Reason: The issue is local and user-assisted, requires processing an attacker-controlled manifest, and has straightforward mitigations while a fix is prepared, such as rejecting non-network source schemes and avoiding untrusted manifests. Acknowledgement: Aisle Research Vulnerability Details: The issue affects URL-based `file` and `archive` sources. In the `file` source path, local `path` inputs are checked against the manifest directory in sandboxed builds, but URL-based inputs take a separate path and do not receive the same confinement check: ```c if (self->url != NULL && self->url[0] != 0) { *is_local = FALSE; return get_download_location (self, is_inline, context, error); } if (self->path != NULL && self->path[0] != 0) { g_autoptr(GFile) file = NULL; *is_local = TRUE; *is_inline = FALSE; file = g_file_resolve_relative_path (base_dir, self->path); if (!builder_context_ensure_parent_dir_sandboxed (context, file, error)) { g_prefix_error (error, "Unable to get source file '%s': ", self->path); return NULL; } ``` The URL is then parsed and passed into the generic download path without a scheme allowlist: ```c g_autoptr(GError) first_error = NULL; g_autoptr(GUri) original_uri = g_uri_parse (url, CONTEXT_HTTP_URI_FLAGS, &first_error); if (original_uri == NULL) { g_propagate_error (error, g_steal_pointer (&first_error)); return FALSE; } g_print ("Downloading %s\n", url); ... if (!builder_download_uri (original_uri, http_referer, disable_http_decompression, dest, checksums, checksums_type, builder_context_get_curl_session (self), &first_error)) ``` The curl download helper accepts the URI as provided and performs the transfer without `CURLOPT_PROTOCOLS` or `CURLOPT_REDIR_PROTOCOLS` restrictions: ```c curl_easy_setopt (session, CURLOPT_URL, url); curl_easy_setopt (session, CURLOPT_REFERER, http_referer); curl_easy_setopt (session, CURLOPT_WRITEFUNCTION, builder_curl_write_cb); curl_easy_setopt (session, CURLOPT_WRITEDATA, &write_data); curl_easy_setopt (session, CURLOPT_ERRORBUFFER, error_buffer); if (!disable_http_decompression) curl_easy_setopt (session, CURLOPT_ACCEPT_ENCODING, ""); write_data.out = out; write_data.checksums = checksums; write_data.n_checksums = n_checksums; write_data.error = error; *error_buffer = '\0'; retcode = curl_easy_perform (session); ``` As a result, a manifest-controlled `file://` URL can read any host file visible to the user running `flatpak-builder`, including when `--sandbox` is enabled, because the sandboxed local-path check only covers `path` sources. The checksum requirement does not prevent exploitation because checksum mismatches disclose the measured digest: ```c g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Wrong %s checksum for %s, expected \"%s\", was \"%s\"", type_name, name, expected_checksum, measured_checksum); ``` With that measured digest, the manifest can be rerun using the correct checksum so the host file is accepted and then incorporated into downloaded sources or build artifacts. Steps to reproduce: 1. Create a manifest with a `type: file` source using a host file URL such as `url: file:///etc/hosts`, and intentionally provide an incorrect `sha256`. 2. Run `flatpak-builder --sandbox <app-dir> <manifest>`. 3. Observe that the failure output reports `Wrong sha256 checksum ... was "<measured>"`, which shows the host file was read. 4. Replace the manifest checksum with the reported value and rerun the build. 5. Observe that the build succeeds and the host file content is copied into the normal source/output path, demonstrating ingestion from outside the manifest directory. Mitigation: Until a fix is released, do not build manifests from untrusted sources. In CI and similar automation, reject `type: file` and `type: archive` `url:` entries whose scheme is not `http`, `https`, or `ftp`, and run builds in isolated environments that do not expose sensitive host files to the build user. Proposed Fix: The minimal fix is to reject disallowed URI schemes before the initial download and before trying mirrors. As defense in depth, the curl session should also set protocol restrictions. ```diff diff --git a/src/builder-context.c b/src/builder-context.c index 1111111..2222222 100644 — a/src/builder-context.c +++ b/src/builder-context.c @@ -401,6 +401,22 @@ builder_context_set_sources_urls (BuilderContext *self, self->sources_urls = g_ptr_array_ref (sources_urls); } +static gboolean +uri_scheme_allowed (GUri *uri) +{ + const char *scheme = g_uri_get_scheme (uri); + return scheme != NULL && + (g_ascii_strcasecmp (scheme, "http") == 0 || + g_ascii_strcasecmp (scheme, "https") == 0 || + g_ascii_strcasecmp (scheme, "ftp") == 0); +} + +static gboolean +reject_disallowed_uri (GUri *uri, GError **error) +{ + return uri_scheme_allowed (uri) ? TRUE : flatpak_fail (error, "Unsupported URL scheme '%s'", g_uri_get_scheme (uri)); +} + gboolean builder_context_download_uri (BuilderContext *self, const char *url, @@ -421,6 +437,9 @@ builder_context_download_uri (BuilderContext *self, return FALSE; } + if (!reject_disallowed_uri (original_uri, error)) + return FALSE; + g_print ("Downloading %s\n", url); @@ -442,6 +461,9 @@ builder_context_download_uri (BuilderContext *self, g_print ("Trying mirror %s\n", mirror_uri_str); g_autoptr(GError) my_error = NULL; + if (!reject_disallowed_uri (mirror_uri, &my_error)) + continue; + if (builder_download_uri (mirror_uri, http_referer, disable_http_decompression, @@ -480,6 +502,10 @@ builder_context_download_uri (BuilderContext *self, return FALSE; } + if (!reject_disallowed_uri (mirror_uri, &mirror_error)) + continue; + g_print ("Trying mirror %s\n", mirrors[i]); if (!builder_download_uri (mirror_uri, http_referer, ``` ------ This report was generated using AI technology. Always review AI-generated content prior to use