Bug 2471600 (CVE-2026-107466) - CVE-2026-107466 flatpak-builder: Local File Exfiltration via `file
Summary: CVE-2026-107466 flatpak-builder: Local File Exfiltration via `file
Keywords:
Status: NEW
Alias: CVE-2026-107466
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Product Security
QA Contact:
URL:
Whiteboard:
Depends On: 2547833
Blocks:
TreeView+ depends on / blocked
 
Reported: 2026-05-11 21:08 UTC by OSIDB Bzimport
Modified: 2026-10-08 07:43 UTC (History)
3 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Embargoed:


Attachments (Terms of Use)

Description OSIDB Bzimport 2026-05-11 21:08:09 UTC
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


Note You need to log in before you can comment on or make changes to this bug.