Hi,
On 09.10.26 11:19, Salvatore Bonaccorso wrote:
FWIW, CVE-2026-107466 was assigned for the GHSA-484h-v688-jq5j issue,
so could you update the changelog as well please as it was not yet
uploaded?
Sure, updated debdiff with both CVE numbers attached.
Felix
diff -Nru flatpak-builder-1.4.4/debian/changelog
flatpak-builder-1.4.4/debian/changelog
--- flatpak-builder-1.4.4/debian/changelog 2025-03-03 18:16:06.000000000
+0100
+++ flatpak-builder-1.4.4/debian/changelog 2026-09-17 21:31:21.000000000
+0200
@@ -1,3 +1,13 @@
+flatpak-builder (1.4.4-2+deb13u1) trixie; urgency=medium
+
+ * Backport security fixes from 1.4.11
+ - Disable git hooks when extracting module source
+ (CVE-2026-86320, GHSA-j5p8-jgjc-f3xv) (Closes: #1147700)
+ - Prevent file:// path traversal when run with --sandbox
+ (CVE-2026-107466, GHSA-484h-v688-jq5j) (Closes: #1147701)
+
+ -- Felix Geyer <[email protected]> Thu, 17 Sep 2026 21:31:21 +0200
+
flatpak-builder (1.4.4-2) unstable; urgency=medium
[ Simon McVittie ]
diff -Nru flatpak-builder-1.4.4/debian/patches/CVE-2026-107466-1.patch
flatpak-builder-1.4.4/debian/patches/CVE-2026-107466-1.patch
--- flatpak-builder-1.4.4/debian/patches/CVE-2026-107466-1.patch
1970-01-01 01:00:00.000000000 +0100
+++ flatpak-builder-1.4.4/debian/patches/CVE-2026-107466-1.patch
2026-09-17 21:20:56.000000000 +0200
@@ -0,0 +1,74 @@
+From f4a082e6ba1f2613f850508e3e895e4bf66a2011 Mon Sep 17 00:00:00 2001
+From: bbhtt <[email protected]>
+Date: Wed, 29 Jul 2026 09:19:58 +0530
+Subject: [PATCH] builder-source-bzr,svn: Validate existence of URL during
+ parsing
+
+Previously it was deep inside download methods.
+---
+ src/builder-source-bzr.c | 13 +++++++++++++
+ src/builder-source-svn.c | 13 +++++++++++++
+ 2 files changed, 26 insertions(+)
+
+diff --git a/src/builder-source-bzr.c b/src/builder-source-bzr.c
+index 244db912..b67a45bb 100644
+--- a/src/builder-source-bzr.c
++++ b/src/builder-source-bzr.c
+@@ -365,6 +365,18 @@ builder_source_bzr_update (BuilderSource *source,
+ return TRUE;
+ }
+
++static gboolean
++builder_source_bzr_validate (BuilderSource *source,
++ GError **error)
++{
++ BuilderSourceBzr *self = BUILDER_SOURCE_BZR (source);
++
++ if (self->url == NULL)
++ return flatpak_fail (error, "URL not specified for bzr source");
++
++ return TRUE;
++}
++
+ static void
+ builder_source_bzr_class_init (BuilderSourceBzrClass *klass)
+ {
+@@ -380,6 +392,7 @@ builder_source_bzr_class_init (BuilderSourceBzrClass
*klass)
+ source_class->bundle = builder_source_bzr_bundle;
+ source_class->update = builder_source_bzr_update;
+ source_class->checksum = builder_source_bzr_checksum;
++ source_class->validate = builder_source_bzr_validate;
+
+ g_object_class_install_property (object_class,
+ PROP_URL,
+diff --git a/src/builder-source-svn.c b/src/builder-source-svn.c
+index c329f50b..905ebc50 100644
+--- a/src/builder-source-svn.c
++++ b/src/builder-source-svn.c
+@@ -390,6 +390,18 @@ builder_source_svn_update (BuilderSource *source,
+ return TRUE;
+ }
+
++static gboolean
++builder_source_svn_validate (BuilderSource *source,
++ GError **error)
++{
++ BuilderSourceSvn *self = BUILDER_SOURCE_SVN (source);
++
++ if (self->url == NULL)
++ return flatpak_fail (error, "URL not specified for svn source");
++
++ return TRUE;
++}
++
+ static void
+ builder_source_svn_class_init (BuilderSourceSvnClass *klass)
+ {
+@@ -405,6 +417,7 @@ builder_source_svn_class_init (BuilderSourceSvnClass
*klass)
+ source_class->bundle = builder_source_svn_bundle;
+ source_class->update = builder_source_svn_update;
+ source_class->checksum = builder_source_svn_checksum;
++ source_class->validate = builder_source_svn_validate;
+
+ g_object_class_install_property (object_class,
+ PROP_URL,
diff -Nru flatpak-builder-1.4.4/debian/patches/CVE-2026-107466-2.patch
flatpak-builder-1.4.4/debian/patches/CVE-2026-107466-2.patch
--- flatpak-builder-1.4.4/debian/patches/CVE-2026-107466-2.patch
1970-01-01 01:00:00.000000000 +0100
+++ flatpak-builder-1.4.4/debian/patches/CVE-2026-107466-2.patch
2026-09-17 21:31:21.000000000 +0200
@@ -0,0 +1,873 @@
+From 99d344ee02c8597ee0a6bbb22be94bfb88e54080 Mon Sep 17 00:00:00 2001
+From: bbhtt <[email protected]>
+Date: Wed, 15 Jul 2026 11:22:23 +0530
+Subject: [PATCH] builder-source: Ensure no source can escape base_dir in
+ sandboxed mode
+
+This extends the features provided by sandboxed mode flag to source
+subclasses missing it previously.
+---
+ src/builder-context.c | 53 ++
+ src/builder-context.h | 8 +
+ src/builder-source-archive.c | 37 +-
+ src/builder-source-bzr.c | 12 +-
+ src/builder-source-file.c | 12 +
+ src/builder-source-git.c | 24 +
+ src/builder-source-patch.c | 24 +-
+ src/builder-source-svn.c | 12 +-
+ tests/Makefile.am.inc | 1 +
+ tests/meson.build | 1 +
+ .../test-sandboxed-mode-source-resolution.sh | 485 ++++++++++++++++++
+ 11 files changed, 654 insertions(+), 15 deletions(-)
+ create mode 100755 tests/test-sandboxed-mode-source-resolution.sh
+
+diff --git a/src/builder-context.c b/src/builder-context.c
+index 1467cc7c..d2153b83 100644
+--- a/src/builder-context.c
++++ b/src/builder-context.c
+@@ -1257,6 +1257,59 @@ builder_context_get_as_url_policy (BuilderContext *self)
+ return self->sdk_config;
+ }
+
++gboolean
++builder_context_resolve_source_uri (BuilderContext *self,
++ const char *url,
++ GFile **out_file,
++ GError **error)
++{
++ const char *scheme;
++
++ *out_file = NULL;
++
++ scheme = g_uri_peek_scheme (url);
++ if (scheme == NULL)
++ return flatpak_fail (error, "Failed to get scheme from URL: '%s'", url);
++
++ if (g_strcmp0 (scheme, "file") == 0)
++ {
++ g_autoptr(GFile) file = g_file_new_for_uri (url);
++
++ if (!builder_context_ensure_file_sandboxed (self, file, error))
++ {
++ g_prefix_error (error, "Unable to use local URL '%s': ", url);
++ return FALSE;
++ }
++
++ *out_file = g_steal_pointer (&file);
++ }
++
++ return TRUE;
++}
++
++char *
++builder_context_resolve_repo_location (BuilderContext *self,
++ const char *url,
++ GError **error)
++{
++
++ g_autoptr(GFile) local_file = NULL;
++
++ if (url == NULL)
++ {
++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "URL not specified");
++ return NULL;
++ }
++
++ if (!builder_context_resolve_source_uri (self, url, &local_file, error))
++ return NULL;
++
++ if (local_file != NULL)
++ return g_file_get_path (local_file);
++
++ return g_strdup (url);
++}
++
+ BuilderContext *
+ builder_context_new (GFile *run_dir,
+ GFile *app_dir,
+diff --git a/src/builder-context.h b/src/builder-context.h
+index f6c12329..21a9132c 100644
+--- a/src/builder-context.h
++++ b/src/builder-context.h
+@@ -190,6 +190,14 @@ BuilderSdkConfig * builder_context_get_sdk_config
(BuilderContext *self);
+
+ BuilderSdkConfig * builder_context_get_sdk_config (BuilderContext *self);
+
++gboolean builder_context_resolve_source_uri (BuilderContext *self,
++ const char *url,
++ GFile **out_file,
++ GError **error);
++char * builder_context_resolve_repo_location (BuilderContext *self,
++ const char *url,
++ GError **error);
++
+ G_DEFINE_AUTOPTR_CLEANUP_FUNC (BuilderContext, g_object_unref)
+
+ G_END_DECLS
+diff --git a/src/builder-source-archive.c b/src/builder-source-archive.c
+index b45b17bf..3f1eb308 100644
+--- a/src/builder-source-archive.c
++++ b/src/builder-source-archive.c
+@@ -406,14 +406,35 @@ get_source_file (BuilderSourceArchive *self,
+
+ if (self->url != NULL && self->url[0] != 0)
+ {
++ g_autoptr(GFile) local_file = NULL;
++
++ if (!builder_context_resolve_source_uri (context, self->url,
&local_file, error))
++ return NULL;
++
++ if (local_file != NULL)
++ {
++ *is_local = TRUE;
++ return g_steal_pointer (&local_file);
++ }
++
+ *is_local = FALSE;
+ return get_download_location (self, context, is_local, error);
+ }
+
+ if (self->path != NULL && self->path[0] != 0)
+ {
++ g_autoptr(GFile) file = NULL;
++
+ *is_local = TRUE;
+- return g_file_resolve_relative_path (base_dir, self->path);
++ 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;
++ }
++
++ return g_steal_pointer (&file);
+ }
+
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "source file path or url
not specified");
+@@ -472,6 +493,20 @@ builder_source_archive_download (BuilderSource *source,
+ return FALSE;
+ }
+
++ if (self->mirror_urls != NULL)
++ {
++ for (size_t i = 0; self->mirror_urls[i] != NULL; i++)
++ {
++ g_autoptr(GFile) mirror_local_file = NULL;
++
++ if (!builder_context_resolve_source_uri (context,
self->mirror_urls[i], &mirror_local_file, error))
++ {
++ g_prefix_error (error, "Invalid mirror-urls entry '%s': ",
self->mirror_urls[i]);
++ return FALSE;
++ }
++ }
++ }
++
+ if (!builder_context_download_uri (context,
+ self->url,
+ (const char **)self->mirror_urls,
+diff --git a/src/builder-source-bzr.c b/src/builder-source-bzr.c
+index b67a45bb..b35fbdd6 100644
+--- a/src/builder-source-bzr.c
++++ b/src/builder-source-bzr.c
+@@ -174,12 +174,12 @@ builder_source_bzr_download (BuilderSource *source,
+ BuilderSourceBzr *self = BUILDER_SOURCE_BZR (source);
+
+ g_autoptr(GFile) mirror_dir = NULL;
++ g_autofree char *repo_location = NULL;
+
+- if (self->url == NULL)
+- {
+- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "URL not specified");
+- return FALSE;
+- }
++ repo_location = builder_context_resolve_repo_location (context, self->url,
error);
++
++ if (repo_location == NULL)
++ return FALSE;
+
+ mirror_dir = get_mirror_dir (self, context);
+
+@@ -205,7 +205,7 @@ builder_source_bzr_download (BuilderSource *source,
+ mirror_dir_tmp = g_file_new_for_path (path_tmp);
+ filename_tmp = g_file_get_basename (mirror_dir_tmp);
+
+- branch_source = self->url;
++ branch_source = repo_location;
+
+ cached_bzr_dir = builder_context_find_in_sources_dirs (context, "bzr",
filename, NULL);
+ if (cached_bzr_dir != NULL)
+diff --git a/src/builder-source-file.c b/src/builder-source-file.c
+index 25434491..d4e57291 100644
+--- a/src/builder-source-file.c
++++ b/src/builder-source-file.c
+@@ -321,6 +321,18 @@ get_source_file (BuilderSourceFile *self,
+
+ if (self->url != NULL && self->url[0] != 0)
+ {
++ g_autoptr(GFile) local_file = NULL;
++
++ if (!builder_context_resolve_source_uri (context, self->url,
&local_file, error))
++ return NULL;
++
++ if (local_file != NULL)
++ {
++ *is_local = TRUE;
++ *is_inline = FALSE;
++ return g_steal_pointer (&local_file);
++ }
++
+ *is_local = FALSE;
+ return get_download_location (self, is_inline, context, error);
+ }
+diff --git a/src/builder-source-git.c b/src/builder-source-git.c
+index cf26ff9b..8d204706 100644
+--- a/src/builder-source-git.c
++++ b/src/builder-source-git.c
+@@ -235,14 +235,38 @@ get_url_or_path (BuilderSourceGit *self,
+ if (scheme == NULL)
+ {
+ repo = g_file_resolve_relative_path (base_dir, self->url);
++
++ if (!builder_context_ensure_parent_dir_sandboxed (context, repo,
error))
++ {
++ g_prefix_error (error, "Unable to get source for git url '%s':
", self->url);
++ return NULL;
++ }
++
+ return g_file_get_uri (repo);
+ }
+
++ if (g_strcmp0 (scheme, "file") == 0)
++ {
++ g_autoptr(GFile) local_file = NULL;
++
++ if (!builder_context_resolve_source_uri (context, self->url,
&local_file, error))
++ return NULL;
++
++ return g_file_get_uri (local_file);
++ }
++
+ return g_strdup (self->url);
+ }
+
+ repo = g_file_resolve_relative_path (base_dir,
+ self->path);
++
++ if (!builder_context_ensure_parent_dir_sandboxed (context, repo, error))
++ {
++ g_prefix_error (error, "Unable to get source file '%s': ", self->path);
++ return NULL;
++ }
++
+ return g_file_get_path (repo);
+ }
+
+diff --git a/src/builder-source-patch.c b/src/builder-source-patch.c
+index a20ecafb..48a9ace3 100644
+--- a/src/builder-source-patch.c
++++ b/src/builder-source-patch.c
+@@ -168,12 +168,32 @@ get_source_files (BuilderSourcePatch *self,
+ int i;
+
+ if ((self->path != NULL && self->path[0] != 0))
+- g_ptr_array_add (res, g_file_resolve_relative_path (base_dir,
self->path));
++ {
++ g_autoptr(GFile) file = g_file_resolve_relative_path (base_dir,
self->path);
++
++ if (!builder_context_ensure_file_sandboxed (context, file, error))
++ {
++ g_prefix_error (error, "Unable to get source file '%s': ",
self->path);
++ return NULL;
++ }
++
++ g_ptr_array_add (res, g_steal_pointer (&file));
++ }
+
+ if (self->paths != NULL)
+ {
+ for (i = 0; self->paths[i] != NULL; i++)
+- g_ptr_array_add (res, g_file_resolve_relative_path (base_dir,
self->paths[i]));
++ {
++ g_autoptr(GFile) file = g_file_resolve_relative_path (base_dir,
self->paths[i]);
++
++ if (!builder_context_ensure_file_sandboxed (context, file, error))
++ {
++ g_prefix_error (error, "Unable to get source file '%s': ",
self->paths[i]);
++ return NULL;
++ }
++
++ g_ptr_array_add (res, g_steal_pointer (&file));
++ }
+ }
+
+ if (res->len == 0)
+diff --git a/src/builder-source-svn.c b/src/builder-source-svn.c
+index 905ebc50..773f5b20 100644
+--- a/src/builder-source-svn.c
++++ b/src/builder-source-svn.c
+@@ -208,14 +208,14 @@ builder_source_svn_download (BuilderSource *source,
+ BuilderSourceSvn *self = BUILDER_SOURCE_SVN (source);
+ g_autoptr(GFile) parent = NULL;
+ g_autofree char *filename = NULL;
++ g_autofree char *repo_location = NULL;
+
+ g_autoptr(GFile) mirror_dir = NULL;
+
+- if (self->url == NULL)
+- {
+- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "URL not specified");
+- return FALSE;
+- }
++ repo_location = builder_context_resolve_repo_location (context, self->url,
error);
++
++ if (repo_location == NULL)
++ return FALSE;
+
+ mirror_dir = get_mirror_dir (self, context, self->revision);
+ parent = g_file_get_parent (mirror_dir);
+@@ -259,7 +259,7 @@ builder_source_svn_download (BuilderSource *source,
+ if (!svn (parent, NULL, error,
+ "checkout", "--non-interactive",
+ "-r", self->revision ? self->revision : "HEAD",
+- self->url, filename_tmp, NULL))
++ repo_location, filename_tmp, NULL))
+ return FALSE;
+ }
+
+diff --git a/tests/Makefile.am.inc b/tests/Makefile.am.inc
+index 8cd31ae6..86a03d0d 100644
+--- a/tests/Makefile.am.inc
++++ b/tests/Makefile.am.inc
+@@ -90,6 +90,7 @@ dist_test_scripts = \
+ tests/test-builder.sh \
+ tests/test-builder-deprecated.sh \
+ tests/test-builder-python.sh \
++ tests/test-sandboxed-mode-source-resolution.sh \
+ $(NULL)
+
+ @VALGRIND_CHECK_RULES@
+diff --git a/tests/meson.build b/tests/meson.build
+index aec77d17..66ae6dbc 100644
+--- a/tests/meson.build
++++ b/tests/meson.build
+@@ -14,6 +14,7 @@ test_names = [
+ 'test-builder',
+ 'test-builder-deprecated',
+ 'test-builder-python',
++ 'test-sandboxed-mode-source-resolution',
+ ]
+
+ tap_test = find_program(
+diff --git a/tests/test-sandboxed-mode-source-resolution.sh
b/tests/test-sandboxed-mode-source-resolution.sh
+new file mode 100755
+index 00000000..e945e0f5
+--- /dev/null
++++ b/tests/test-sandboxed-mode-source-resolution.sh
+@@ -0,0 +1,506 @@
++#!/bin/bash
++#
++# Copyright (C) 2026 Boudhayan Bhattacharya <[email protected]>
++#
++# This library is free software; you can redistribute it and/or
++# modify it under the terms of the GNU Lesser General Public
++# License as published by the Free Software Foundation; either
++# version 2 of the License, or (at your option) any later version.
++#
++# This library is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# Lesser General Public License for more details.
++#
++# You should have received a copy of the GNU Lesser General Public
++# License along with this library; if not, write to the
++# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++# Boston, MA 02111-1307, USA.
++
++
++set -euo pipefail
++
++. $(dirname $0)/libtest.sh
++
++skip_without_fuse
++
++echo "1..15"
++
++setup_repo
++install_repo
++setup_sdk_repo
++install_sdk_repo
++
++cd "$TEST_DATA_DIR"
++
++_run_build () {
++ if [ -n "${BUILD_LOG:-}" ]; then
++ ${FLATPAK_BUILDER} --force-clean \
++ "appdir" "$@" >&2 2>"$BUILD_LOG"
++ else
++ ${FLATPAK_BUILDER} --force-clean \
++ "appdir" "$@" >&2
++ fi
++}
++
++run_build () {
++ _run_build "$@"
++}
++
++run_build_fail () {
++ if _run_build "$@"; then
++ echo "build of ${!#} unexpectedly succeeded" >&2
++ exit 1
++ fi
++}
++
++
++mkdir file-workdir
++cd file-workdir
++
++CURDIR="$(pwd)"
++
++echo "test" > test.txt
++
++SHA=$(sha256sum test.txt | awk '{print $1}')
++
++cat > test-path-inside.json <<'EOF'
++{
++ "app-id": "org.test.sandbox_path_inside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [
++ "cp test.txt /app/test.txt"
++ ],
++ "sources": [{
++ "type": "file",
++ "path": "test.txt"
++ }]
++ }]
++}
++EOF
++
++run_build --sandbox test-path-inside.json
++assert_has_file appdir/files/test.txt
++assert_file_has_content appdir/files/test.txt 'test'
++
++echo "ok path source inside manifest tree works for file type in sandboxed
mode"
++
++cat > test-file-url-inside.json <<EOF
++{
++ "app-id": "org.test.sandbox_file_url_inside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [
++ "cp test.txt /app/test.txt"
++ ],
++ "sources": [{
++ "type": "file",
++ "url": "file://$CURDIR/test.txt",
++ "sha256": "$SHA"
++ }]
++ }]
++}
++EOF
++
++run_build --sandbox test-file-url-inside.json
++assert_has_file appdir/files/test.txt
++assert_file_has_content appdir/files/test.txt 'test'
++
++echo "ok file URI source inside manifest tree works for file type in
sandboxed mode"
++
++mkdir tmp_1
++cd tmp_1
++
++cat > test-path-outside.json <<'EOF'
++{
++ "app-id": "org.test.sandbox_path_outside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [],
++ "sources": [{
++ "type": "file",
++ "path": "../test.txt"
++ }]
++ }]
++}
++EOF
++
++BUILD_LOG=build-log-file-path-outside run_build_fail --sandbox \
++ test-path-outside.json
++assert_file_has_content build-log-file-path-outside 'not inside manifest
directory'
++
++echo "ok path source outside manifest tree is rejected for file type in
sandboxed mode"
++
++cat > test-file-url-outside.json <<EOF
++{
++ "app-id": "org.test.sandbox_file_url_outside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [],
++ "sources": [{
++ "type": "file",
++ "url": "file://$CURDIR/test.txt",
++ "sha256": "$SHA"
++ }]
++ }]
++}
++EOF
++
++BUILD_LOG=build-log-file-url-outside run_build_fail --sandbox \
++ test-file-url-outside.json
++assert_file_has_content build-log-file-url-outside 'not inside manifest
directory'
++
++echo "ok file URI source outside manifest tree is rejected for file type in
sandboxed mode"
++
++cd "$TEST_DATA_DIR"
++mkdir archive-workdir
++cd archive-workdir
++
++CURDIR="$(pwd)"
++
++mkdir -p archive-src
++echo "archived content" > archive-src/file.txt
++tar -czf archive-src.tar.gz -C archive-src .
++
++SHA=$(sha256sum archive-src.tar.gz | awk '{print $1}')
++
++cat > test-archive-path-inside.json <<'EOF'
++{
++ "app-id": "org.test.sandbox_archive_path_inside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [
++ "cp file.txt /app/file.txt"
++ ],
++ "sources": [{
++ "type": "archive",
++ "path": "archive-src.tar.gz"
++ }]
++ }]
++}
++EOF
++
++run_build --sandbox test-archive-path-inside.json
++assert_has_file appdir/files/file.txt
++assert_file_has_content appdir/files/file.txt 'archived content'
++
++echo "ok path source inside manifest tree works for archive type in sandboxed
mode"
++
++cat > test-archive-file_uri-inside.json <<EOF
++{
++ "app-id": "org.test.sandbox_archive_file_uri_inside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [
++ "cp file.txt /app/file.txt"
++ ],
++ "sources": [{
++ "type": "archive",
++ "url": "file://$CURDIR/archive-src.tar.gz",
++ "sha256": "$SHA"
++ }]
++ }]
++}
++EOF
++
++run_build --sandbox test-archive-file_uri-inside.json
++assert_has_file appdir/files/file.txt
++assert_file_has_content appdir/files/file.txt 'archived content'
++
++echo "ok file URI source inside manifest tree works for archive type in
sandboxed mode"
++
++mkdir tmp_1
++cd tmp_1
++
++cat > test-archive-path-outside.json <<'EOF'
++{
++ "app-id": "org.test.sandbox_archive_path_outside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [],
++ "sources": [{
++ "type": "archive",
++ "path": "../archive-src.tar.gz"
++ }]
++ }]
++}
++EOF
++
++BUILD_LOG=build-log-archive-path-outside run_build_fail --sandbox \
++ test-archive-path-outside.json
++assert_file_has_content build-log-archive-path-outside 'not inside manifest
directory'
++
++echo "ok path source outside manifest tree is rejected for archive type in
sandboxed mode"
++
++cat > test-archive-file_uri-outside.json <<EOF
++{
++ "app-id": "org.test.sandbox_archive_file_uri_outside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [],
++ "sources": [{
++ "type": "archive",
++ "url": "file://$CURDIR/archive-src.tar.gz",
++ "sha256": "$SHA"
++ }]
++ }]
++}
++EOF
++
++BUILD_LOG=build-log-archive-file_uri-outside run_build_fail --sandbox \
++ test-archive-file_uri-outside.json
++assert_file_has_content build-log-archive-file_uri-outside 'not inside
manifest directory'
++
++echo "ok file URI source outside manifest tree is rejected for archive type
in sandboxed mode"
++
++cp ../archive-src.tar.gz .
++
++cat > test-archive-mirror_uri-outside.json <<EOF
++{
++ "app-id": "org.test.sandbox_archive_mirror_uri_outside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [],
++ "sources": [{
++ "type": "archive",
++ "url": "https://example.org/archive-src.tar.gz",
++ "mirror-urls": ["file://$CURDIR/archive-src.tar.gz"],
++ "sha256": "$SHA"
++ }]
++ }]
++}
++EOF
++
++BUILD_LOG=build-log-archive-mirror_uri-outside run_build_fail --sandbox \
++ test-archive-mirror_uri-outside.json
++assert_file_has_content build-log-archive-mirror_uri-outside 'not inside
manifest directory'
++
++echo "ok mirror URI source outside manifest tree is rejected for archive type
in sandboxed mode"
++
++cd "$TEST_DATA_DIR"
++mkdir patch-workdir
++cd patch-workdir
++
++mkdir -p archive-src
++echo "archived content" > archive-src/file.txt
++tar -czf archive-src.tar.gz -C archive-src .
++
++cat > fix.patch <<'EOF'
++--- a/file.txt
+++++ b/file.txt
++@@ -1 +1 @@
++-archived content
+++patched content
++EOF
++
++cat > test-patch-path-inside.json <<'EOF'
++{
++ "app-id": "org.test.sandbox_patch_path_inside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [
++ "cp file.txt /app"
++ ],
++ "sources": [
++ {
++ "type": "archive",
++ "path": "archive-src.tar.gz"
++ },
++ {
++ "type": "patch",
++ "path": "fix.patch"
++ }
++ ]
++ }]
++}
++EOF
++
++run_build --sandbox test-patch-path-inside.json
++assert_has_file appdir/files/file.txt
++assert_file_has_content appdir/files/file.txt 'patched content'
++
++echo "ok path source inside manifest tree works for patch type in sandboxed
mode"
++
++mkdir tmp_1
++cp archive-src.tar.gz tmp_1/
++cd tmp_1
++
++cat > test-patch-path-outside.json <<'EOF'
++{
++ "app-id": "org.test.sandbox_patch_path_outside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [],
++ "sources": [
++ {
++ "type": "archive",
++ "path": "archive-src.tar.gz"
++ },
++ {
++ "type": "patch",
++ "path": "../fix.patch"
++ }
++ ]
++ }]
++}
++EOF
++
++BUILD_LOG=build-log-patch-path-outside run_build_fail --sandbox \
++ test-patch-path-outside.json
++assert_file_has_content build-log-patch-path-outside 'not inside manifest
directory'
++
++echo "ok path source outside manifest tree is rejected for patch type in
sandboxed mode"
++
++cd "$TEST_DATA_DIR"
++mkdir git-workdir
++cd git-workdir
++
++CURDIR="$(pwd)"
++
++mkdir git-repo
++( cd git-repo \
++ && git -c init.defaultBranch=test init -q \
++ && git config --local user.email "[email protected]" \
++ && git config --local user.name "test" \
++ && echo "git content" > file.txt \
++ && git add file.txt \
++ && git commit -q -m "Add file" )
++
++
++cat > test-git-path-inside.json <<'EOF'
++{
++ "app-id": "org.test.sandbox_git_path_inside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [
++ "cp file.txt /app/file.txt"
++ ],
++ "sources": [{
++ "type": "git",
++ "path": "git-repo",
++ "branch": "test"
++ }]
++ }]
++}
++EOF
++
++run_build --sandbox test-git-path-inside.json
++assert_has_file appdir/files/file.txt
++assert_file_has_content appdir/files/file.txt 'git content'
++
++echo "ok path source inside manifest tree works for git type in sandboxed
mode"
++
++cat > test-git-file_uri-inside.json <<EOF
++{
++ "app-id": "org.test.sandbox_git_file_uri_inside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [
++ "cp file.txt /app/file.txt"
++ ],
++ "sources": [{
++ "type": "git",
++ "url": "file://$CURDIR/git-repo",
++ "branch": "test"
++ }]
++ }]
++}
++EOF
++
++run_build --sandbox test-git-file_uri-inside.json
++assert_has_file appdir/files/file.txt
++assert_file_has_content appdir/files/file.txt 'git content'
++
++echo "ok file URI source inside manifest tree works for git type in sandboxed
mode"
++
++mkdir tmp_1
++cd tmp_1
++
++cat > test-git-path-outside.json <<'EOF'
++{
++ "app-id": "org.test.sandbox_git_path_outside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [],
++ "sources": [{
++ "type": "git",
++ "path": "../git-repo",
++ "branch": "test"
++ }]
++ }]
++}
++EOF
++
++BUILD_LOG=build-log-git-path-outside run_build_fail --sandbox \
++ test-git-path-outside.json
++assert_file_has_content build-log-git-path-outside 'not inside manifest
directory'
++
++echo "ok path source outside manifest tree is rejected for git type in
sandboxed mode"
++
++cat > test-git-file_uri-outside.json <<EOF
++{
++ "app-id": "org.test.sandbox_git_file_uri_outside",
++ "runtime": "org.test.Platform",
++ "sdk": "org.test.Sdk",
++ "modules": [{
++ "name": "test",
++ "buildsystem": "simple",
++ "build-commands": [],
++ "sources": [{
++ "type": "git",
++ "url": "file://$CURDIR/git-repo",
++ "branch": "test"
++ }]
++ }]
++}
++EOF
++
++BUILD_LOG=build-log-git-file_uri-outside run_build_fail --sandbox \
++ test-git-file_uri-outside.json
++assert_file_has_content build-log-git-file_uri-outside 'not inside manifest
directory'
++
++echo "ok file URI source outside manifest tree is rejected for git type in
sandboxed mode"
++
diff -Nru flatpak-builder-1.4.4/debian/patches/CVE-2026-107466-3.patch
flatpak-builder-1.4.4/debian/patches/CVE-2026-107466-3.patch
--- flatpak-builder-1.4.4/debian/patches/CVE-2026-107466-3.patch
1970-01-01 01:00:00.000000000 +0100
+++ flatpak-builder-1.4.4/debian/patches/CVE-2026-107466-3.patch
2026-09-17 21:30:47.000000000 +0200
@@ -0,0 +1,114 @@
+From f18fcd4069ed5c33566527fea5a18634b1d6f3f4 Mon Sep 17 00:00:00 2001
+From: bbhtt <[email protected]>
+Date: Sat, 12 Sep 2026 16:33:47 +0530
+Subject: [PATCH] builder-source-archive,file: Abort on invalid checksum
+ strings
+
+The checksum string is user controlled and used in various places
+to control paths. We should verify the string early to make sure
+it matches the expected hash format and length, to avoid potential
+path traversal issues.
+---
+ src/builder-source-archive.c | 2 +-
+ src/builder-source-file.c | 2 +-
+ src/builder-utils.c | 43 ++++++++++++++++++++++++++++++++++++
+ src/builder-utils.h | 9 ++++++++
+ 4 files changed, 54 insertions(+), 2 deletions(-)
+
+diff --git a/src/builder-source-archive.c b/src/builder-source-archive.c
+index 3f1eb308..1db159b1 100644
+--- a/src/builder-source-archive.c
++++ b/src/builder-source-archive.c
+@@ -320,7 +320,7 @@ builder_source_archive_validate (BuilderSource *source,
+ strchr (self->dest_filename, '/') != NULL)
+ return flatpak_fail (error, "No slashes allowed in dest-filename, use
dest property for directory");
+
+- return TRUE;
++ return builder_validate_source_checksums (self->md5, self->sha1,
self->sha256, self->sha512, error);
+ }
+
+ static GUri *
+diff --git a/src/builder-source-file.c b/src/builder-source-file.c
+index d4e57291..d2dcdfa1 100644
+--- a/src/builder-source-file.c
++++ b/src/builder-source-file.c
+@@ -231,7 +231,7 @@ builder_source_file_validate (BuilderSource *source,
+ strchr (self->dest_filename, '/') != NULL)
+ return flatpak_fail (error, "No slashes allowed in dest-filename, use
dest property for directory");
+
+- return TRUE;
++ return builder_validate_source_checksums (self->md5, self->sha1,
self->sha256, self->sha512, error);
+ }
+
+
+diff --git a/src/builder-utils.c b/src/builder-utils.c
+index 5a097250..6913c017 100644
+--- a/src/builder-utils.c
++++ b/src/builder-utils.c
+@@ -2088,3 +2088,46 @@ appstream_has_version (int major,
+
+ return FALSE;
+ }
++
++gboolean
++builder_validate_checksum_string (const char *arg,
++ gsize len)
++{
++ if (arg == NULL || strlen (arg) != len)
++ return FALSE;
++
++ while (*arg != '\0')
++ {
++ if (!g_ascii_isxdigit (*arg))
++ return FALSE;
++ arg++;
++ }
++
++ return TRUE;
++}
++
++gboolean
++builder_validate_source_checksums (const char *md5,
++ const char *sha1,
++ const char *sha256,
++ const char *sha512,
++ GError **error)
++{
++ if (md5 != NULL && md5[0] != '\0' &&
++ !builder_validate_checksum_string (md5, 32))
++ return flatpak_fail (error, "Invalid md5 checksum string");
++
++ if (sha1 != NULL && sha1[0] != '\0' &&
++ !builder_validate_checksum_string (sha1, 40))
++ return flatpak_fail (error, "Invalid sha1 checksum string");
++
++ if (sha256 != NULL && sha256[0] != '\0' &&
++ !builder_validate_checksum_string (sha256, 64))
++ return flatpak_fail (error, "Invalid sha256 checksum string");
++
++ if (sha512 != NULL && sha512[0] != '\0' &&
++ !builder_validate_checksum_string (sha512, 128))
++ return flatpak_fail (error, "Invalid sha512 checksum string");
++
++ return TRUE;
++}
+diff --git a/src/builder-utils.h b/src/builder-utils.h
+index 5e4a11d7..e2a5cfb8 100644
+--- a/src/builder-utils.h
++++ b/src/builder-utils.h
+@@ -224,6 +224,15 @@ gboolean appstream_has_version (int major,
+ int minor,
+ int micro);
+
++gboolean builder_validate_checksum_string (const char *arg,
++ gsize len);
++
++gboolean builder_validate_source_checksums (const char *md5,
++ const char *sha1,
++ const char *sha256,
++ const char *sha512,
++ GError **error);
++
+ G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakXml, flatpak_xml_free);
+
+ G_END_DECLS
diff -Nru flatpak-builder-1.4.4/debian/patches/CVE-2026-86320.patch
flatpak-builder-1.4.4/debian/patches/CVE-2026-86320.patch
--- flatpak-builder-1.4.4/debian/patches/CVE-2026-86320.patch 1970-01-01
01:00:00.000000000 +0100
+++ flatpak-builder-1.4.4/debian/patches/CVE-2026-86320.patch 2026-09-17
21:31:21.000000000 +0200
@@ -0,0 +1,34 @@
+From de7e1a0580707638b21d46d0b9401088133f3a5c Mon Sep 17 00:00:00 2001
+From: bbhtt <[email protected]>
+Date: Mon, 10 Aug 2026 07:20:29 +0530
+Subject: [PATCH] builder-source-patch: Disable git hooks completely when
+ applying patches
+
+git runs unsandboxed on host in this stage and a malicious source
+can include a post-applypatch which will cause a code execution on host
+
+A better fix would be to sandbox these external commands but f-b is
+not currently structured like that.
+---
+ src/builder-source-patch.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/src/builder-source-patch.c b/src/builder-source-patch.c
+index eedd7b29..a20ecafb 100644
+--- a/src/builder-source-patch.c
++++ b/src/builder-source-patch.c
+@@ -250,10 +250,14 @@ patch (GFile *dir,
+ args = g_ptr_array_new ();
+ if (use_git) {
+ g_ptr_array_add (args, "git");
++ g_ptr_array_add (args, "-c");
++ g_ptr_array_add (args, "core.hooksPath=/dev/null");
+ g_ptr_array_add (args, "apply");
+ g_ptr_array_add (args, "-v");
+ } else if (use_git_am) {
+ g_ptr_array_add (args, "git");
++ g_ptr_array_add (args, "-c");
++ g_ptr_array_add (args, "core.hooksPath=/dev/null");
+ g_ptr_array_add (args, "am");
+ g_ptr_array_add (args, "--keep-cr");
+ } else {
diff -Nru flatpak-builder-1.4.4/debian/patches/series
flatpak-builder-1.4.4/debian/patches/series
--- flatpak-builder-1.4.4/debian/patches/series 1970-01-01 01:00:00.000000000
+0100
+++ flatpak-builder-1.4.4/debian/patches/series 2026-09-17 21:31:21.000000000
+0200
@@ -0,0 +1,4 @@
+CVE-2026-86320.patch
+CVE-2026-107466-1.patch
+CVE-2026-107466-2.patch
+CVE-2026-107466-3.patch