Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:flatpak-builder
User: [email protected]
Usertags: pu

[ Reason ]
Fixes for CVE-2026-86320 and GHSA-484h-v688-jq5j

[ Impact ]
Code execution and file access on the host when building flatpaks.

[ Tests ]
The fix for GHSA-484h-v688-jq5j has a unit test that is run as part of
the autopkgtest.
CVE-2026-86320 has a PoC that I've manually verified.

[ Risks ]
The largest change has good test coverage. The rest are relatively simple fixes.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]
Backport of the upstream security fixes.
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
+      (no known CVE ID, 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-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/GHSA-484h-v688-jq5j-1.patch 
flatpak-builder-1.4.4/debian/patches/GHSA-484h-v688-jq5j-1.patch
--- flatpak-builder-1.4.4/debian/patches/GHSA-484h-v688-jq5j-1.patch    
1970-01-01 01:00:00.000000000 +0100
+++ flatpak-builder-1.4.4/debian/patches/GHSA-484h-v688-jq5j-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/GHSA-484h-v688-jq5j-2.patch 
flatpak-builder-1.4.4/debian/patches/GHSA-484h-v688-jq5j-2.patch
--- flatpak-builder-1.4.4/debian/patches/GHSA-484h-v688-jq5j-2.patch    
1970-01-01 01:00:00.000000000 +0100
+++ flatpak-builder-1.4.4/debian/patches/GHSA-484h-v688-jq5j-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/GHSA-484h-v688-jq5j-3.patch 
flatpak-builder-1.4.4/debian/patches/GHSA-484h-v688-jq5j-3.patch
--- flatpak-builder-1.4.4/debian/patches/GHSA-484h-v688-jq5j-3.patch    
1970-01-01 01:00:00.000000000 +0100
+++ flatpak-builder-1.4.4/debian/patches/GHSA-484h-v688-jq5j-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/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
+GHSA-484h-v688-jq5j-1.patch
+GHSA-484h-v688-jq5j-2.patch
+GHSA-484h-v688-jq5j-3.patch

Reply via email to