Your message dated Sat, 11 Jul 2026 10:42:31 +0000
with message-id <[email protected]>
and subject line Released in 12.15
has caused the Debian Bug report #1138706,
regarding bookworm-pu: package sshfs-fuse/3.7.3-1.2~deb12u1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
1138706: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1138706
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: [email protected], [email protected], 
[email protected]
Control: affects -1 + src:sshfs-fuse
User: [email protected]
Usertags: pu

Hi SRM

[ Reason ]
sshfs-fuse is affected by two CVEs:
- Improper Neutralization of Argument Delimiters in a Command
  ('Argument Injection') in sshfs (CVE-2026-48711)
- Symlink Escape: Rogue SFTP Server → Local File Read/Write
  (CVE-2026-47187)

While they are marked for the later one 'critical' from upstream they
need a rogue server at first place. So we think it does not warrant a
DSA.

[ Impact ]
If not updating remains vulnerable to those two CVEs.

[ Tests ]
Some manual tests. Unfortunately the test suite is disabled since
3.7.3-1.1.

[ Risks ]
The symlink CVE introduces a new contain_symlink option as has a
default as on, and will reject absolute symlinks targets and targets
containing '..' components, and returning EPERM. This can be
considered a behaviour changes but was according to upstream the
simplest rule to apply for beeing enough against the thread model
describd. So I think we need ot go for it. If in doupt, we can have
the uploads not yet accepted and give the unstable version bit more
exposure.

[ 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 ]
 * Add contain_symlinks option to prevent symlink escape attacks 
(CVE-2026-47187)
 * Reject hostname option injection via bracketed mount source (CVE-2026-48711)

[ Other info ]
The unstable version has not yet migrated to testing.

Regards,
Salvatore
diff -Nru sshfs-fuse-3.7.3/debian/changelog sshfs-fuse-3.7.3/debian/changelog
--- sshfs-fuse-3.7.3/debian/changelog   2023-02-07 20:33:53.000000000 +0100
+++ sshfs-fuse-3.7.3/debian/changelog   2026-06-02 13:13:13.000000000 +0200
@@ -1,3 +1,20 @@
+sshfs-fuse (3.7.3-1.2~deb12u1) bookworm; urgency=medium
+
+  * Non-maintainer upload.
+  * Rebuild for bookworm
+
+ -- Salvatore Bonaccorso <[email protected]>  Tue, 02 Jun 2026 13:13:13 +0200
+
+sshfs-fuse (3.7.3-1.2) unstable; urgency=high
+
+  * Non-maintainer upload.
+  * add contain_symlinks option to prevent symlink escape attacks
+    (CVE-2026-47187) (Closes: #1138293)
+  * reject hostname option injection via bracketed mount source 
(CVE-2026-48711)
+    (Closes: #1138293)
+
+ -- Salvatore Bonaccorso <[email protected]>  Sat, 30 May 2026 17:20:39 +0200
+
 sshfs-fuse (3.7.3-1.1) unstable; urgency=high
 
   * Non-maintainer upload.
diff -Nru 
sshfs-fuse-3.7.3/debian/patches/add-contain_symlinks-option-to-prevent-symlink-escap.patch
 
sshfs-fuse-3.7.3/debian/patches/add-contain_symlinks-option-to-prevent-symlink-escap.patch
--- 
sshfs-fuse-3.7.3/debian/patches/add-contain_symlinks-option-to-prevent-symlink-escap.patch
  1970-01-01 01:00:00.000000000 +0100
+++ 
sshfs-fuse-3.7.3/debian/patches/add-contain_symlinks-option-to-prevent-symlink-escap.patch
  2026-06-02 13:12:58.000000000 +0200
@@ -0,0 +1,160 @@
+From: Abhinav Agarwal <[email protected]>
+Date: Sun, 17 May 2026 01:27:17 -0700
+Subject: add contain_symlinks option to prevent symlink escape attacks
+Origin: 
https://github.com/libfuse/sshfs/commit/bcd132f17ccf1b8592a229df797c9b08883fec26
+Bug: https://github.com/libfuse/sshfs/pull/361
+Bug-Debian: https://bugs.debian.org/1138293
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-47187
+
+A malicious SFTP server can return symlink targets that the local
+kernel VFS resolves outside the mount root, enabling local file reads
+or writes through ordinary operations like cp following a symlink.
+
+Add a contain_symlinks option (default on) that rejects absolute
+symlink targets and any target containing a `..` component, returning
+EPERM. Users who need legacy pass-through for trusted servers can opt
+out with -o no_contain_symlinks.
+
+The check is purely lexical and deliberately strict: in an adversarial
+filesystem the server controls intermediate path components, so any
+non-`..` component could be a symlink anywhere, making lexical depth
+tracking unreliable. Rejecting absolute and any `..` is the simplest
+rule that is provably complete against the threat model.
+
+transform_symlinks composes poorly with containment because transformed
+results often contain `..`; a warning is emitted when both are enabled.
+
+Tests cover default-on containment (readlink + open/stat traversal),
+opt-out behavior, transform_symlinks interaction (both arms), and
+option precedence.
+---
+ sshfs.c            |  50 +++++++++++++
+ sshfs.rst          |  15 ++++
+ test/test_sshfs.py | 170 +++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 235 insertions(+)
+
+--- a/sshfs.c
++++ b/sshfs.c
+@@ -312,6 +312,7 @@ struct sshfs {
+       int fstat_workaround;
+       int createmode_workaround;
+       int transform_symlinks;
++      int contain_symlinks;
+       int follow_symlinks;
+       int no_check_root;
+       int detect_uid;
+@@ -493,6 +494,8 @@ static struct fuse_opt sshfs_opts[] = {
+       SSHFS_OPT("sshfs_verbose",     verbose, 1),
+       SSHFS_OPT("reconnect",         reconnect, 1),
+       SSHFS_OPT("transform_symlinks", transform_symlinks, 1),
++      SSHFS_OPT("contain_symlinks", contain_symlinks, 1),
++      SSHFS_OPT("no_contain_symlinks", contain_symlinks, 0),
+       SSHFS_OPT("follow_symlinks",   follow_symlinks, 1),
+       SSHFS_OPT("no_check_root",     no_check_root, 1),
+       SSHFS_OPT("password_stdin",    password_stdin, 1),
+@@ -2104,6 +2107,36 @@ static void strip_common(const char **sp
+       } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t));
+ }
+ 
++/*
++ * Reject symlink targets that could escape the mount root: absolute
++ * paths and any target containing a ".." component.  Returns 1 if
++ * the target is safe to expose to the kernel, 0 otherwise.
++ */
++static int symlink_target_is_contained(const char *target)
++{
++      const char *p = target;
++
++      if (*p == '/')
++              return 0;
++
++      while (*p) {
++              const char *comp = p;
++
++              while (*p && *p != '/')
++                      p++;
++              /*
++               * Reject any ".." rather than try to normalize: in an
++               * adversarial filesystem the server controls intermediate
++               * components, so lexical normalization cannot be trusted.
++               */
++              if (p - comp == 2 && comp[0] == '.' && comp[1] == '.')
++                      return 0;
++              while (*p == '/')
++                      p++;
++      }
++      return 1;
++}
++
+ static void transform_symlink(const char *path, char **linkp)
+ {
+       const char *l = *linkp;
+@@ -2168,6 +2201,13 @@ static int sshfs_readlink(const char *pa
+                  buf_get_string(&name, &link) != -1) {
+                       if (sshfs.transform_symlinks)
+                               transform_symlink(path, &link);
++                      if (sshfs.contain_symlinks &&
++                          !symlink_target_is_contained(link)) {
++                              free(link);
++                              buf_free(&name);
++                              buf_free(&buf);
++                              return -EPERM;
++                      }
+                       strncpy(linkbuf, link, size - 1);
+                       linkbuf[size - 1] = '\0';
+                       free(link);
+@@ -3641,6 +3681,9 @@ static void usage(const char *progname)
+ "    -o passive             communicate over stdin and stdout bypassing 
network\n"
+ "    -o disable_hardlink    link(2) will return with errno set to ENOSYS\n"
+ "    -o transform_symlinks  transform absolute symlinks to relative\n"
++"    -o contain_symlinks    reject absolute symlinks and symlinks containing 
..\n"
++"                           (enabled by default; disable with 
no_contain_symlinks)\n"
++"    -o no_contain_symlinks allow all symlink targets including absolute and 
..\n"
+ "    -o follow_symlinks     follow symlinks on the server\n"
+ "    -o no_check_root       don't check for existence of 'dir' on server\n"
+ "    -o password_stdin      read password from stdin (only for pam_mount!)\n"
+@@ -4187,6 +4230,7 @@ int main(int argc, char *argv[])
+       sshfs.max_conns = 1;
+       sshfs.ptyfd = -1;
+       sshfs.dir_cache = 1;
++      sshfs.contain_symlinks = 1;
+       sshfs.show_help = 0;
+       sshfs.show_version = 0;
+       sshfs.singlethread = 0;
+@@ -4237,6 +4281,12 @@ int main(int argc, char *argv[])
+               exit(1);
+       }
+ 
++      if (sshfs.transform_symlinks && sshfs.contain_symlinks)
++              fprintf(stderr, "warning: transform_symlinks with "
++                      "contain_symlinks may reject transformed links "
++                      "containing '..' - consider adding "
++                      "-o no_contain_symlinks\n");
++
+       if (sshfs.idmap == IDMAP_USER)
+               sshfs.detect_uid = 1;
+       else if (sshfs.idmap == IDMAP_FILE) {
+--- a/sshfs.rst
++++ b/sshfs.rst
+@@ -172,6 +172,21 @@ Options
+    ``/foo/bar/com`` is a symlink to ``/foo/blub``, SSHFS will
+    transform the link target to ``../blub`` on the client side.
+ 
++-o contain_symlinks
++   reject symlink targets that are absolute or contain ``..``
++   components.  When a blocked symlink is encountered, readlink
++   returns EPERM.  This is enabled by default to prevent a
++   malicious server from inducing local file reads or writes
++   through crafted symlink targets.  Note that this is stricter
++   than ``transform_symlinks``: the two options should not normally
++   be combined, since transformed results often contain ``..``
++   and would be rejected by containment.
++
++-o no_contain_symlinks
++   disable symlink containment and allow all symlink targets
++   through unchanged, including absolute paths and paths
++   containing ``..``.  Only use this with fully trusted servers.
++
+ -o follow_symlinks
+    follow symlinks on the server, i.e. present them as regular
+    files on the client. If a symlink is dangling (i.e, the target does
diff -Nru 
sshfs-fuse-3.7.3/debian/patches/reject-hostname-option-injection-via-bracketed-mount.patch
 
sshfs-fuse-3.7.3/debian/patches/reject-hostname-option-injection-via-bracketed-mount.patch
--- 
sshfs-fuse-3.7.3/debian/patches/reject-hostname-option-injection-via-bracketed-mount.patch
  1970-01-01 01:00:00.000000000 +0100
+++ 
sshfs-fuse-3.7.3/debian/patches/reject-hostname-option-injection-via-bracketed-mount.patch
  2026-06-02 13:12:58.000000000 +0200
@@ -0,0 +1,136 @@
+From: Abhinav Agarwal <[email protected]>
+Date: Fri, 29 May 2026 15:38:43 -0700
+Subject: reject hostname option injection via bracketed mount source
+Origin: 
https://github.com/libfuse/sshfs/commit/29bb565ea6405e2dd5a0ea65fe64da117e76055e
+Bug: https://github.com/libfuse/sshfs/pull/362
+Bug-Debian: https://bugs.debian.org/1138293
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-48711
+
+A source like [-oProxyCommand=CMD]:/path passes the bracket-parsing
+check in find_base_path() and ends up as -oProxyCommand=CMD in the
+ssh argv.  When sftp_server is a path, ssh gets a destination argument
+and executes the injected ProxyCommand before connecting.
+
+Reject hostnames starting with - after bracket stripping, and add --
+before the hostname in the ssh command line so positional args can't
+be misread as options.
+---
+ sshfs.c                          |  8 ++++-
+ test/meson.build                 |  2 +-
+ test/test_hostname_validation.py | 60 ++++++++++++++++++++++++++++++++
+ 3 files changed, 68 insertions(+), 2 deletions(-)
+ create mode 100644 test/test_hostname_validation.py
+
+diff --git a/sshfs.c b/sshfs.c
+index 1bb83c765e2f..67d6a247181e 100644
+--- a/sshfs.c
++++ b/sshfs.c
+@@ -4019,6 +4019,11 @@ static char *find_base_path(void)
+       *d++ = '\0';
+       s++;
+ 
++      if (sshfs.host[0] == '-') {
++              fprintf(stderr, "invalid hostname '%s'\n", sshfs.host);
++              exit(1);
++      }
++
+       return s;
+ }
+ 
+@@ -4410,7 +4415,6 @@ int main(int argc, char *argv[])
+       tmp = g_strdup_printf("-%i", sshfs.ssh_ver);
+       ssh_add_arg(tmp);
+       g_free(tmp);
+-      ssh_add_arg(sshfs.host);
+       if (sshfs.sftp_server)
+               sftp_server = sshfs.sftp_server;
+       else if (sshfs.ssh_ver == 1)
+@@ -4421,6 +4425,8 @@ int main(int argc, char *argv[])
+       if (sshfs.ssh_ver != 1 && strchr(sftp_server, '/') == NULL)
+               ssh_add_arg("-s");
+ 
++      ssh_add_arg("--");
++      ssh_add_arg(sshfs.host);
+       ssh_add_arg(sftp_server);
+       free(sshfs.sftp_server);
+ 
+diff --git a/test/meson.build b/test/meson.build
+index c0edde2d0482..4b26321f482d 100644
+--- a/test/meson.build
++++ b/test/meson.build
+@@ -1,5 +1,5 @@
+ test_scripts = [ 'conftest.py', 'pytest.ini', 'test_sshfs.py',
+-                 'util.py' ]
++                 'test_hostname_validation.py', 'util.py' ]
+ custom_target('test_scripts', input: test_scripts,
+               output: test_scripts, build_by_default: true,
+               command: ['cp', '-fPp',
+diff --git a/test/test_hostname_validation.py 
b/test/test_hostname_validation.py
+new file mode 100644
+index 000000000000..07b0c4f2bf04
+--- /dev/null
++++ b/test/test_hostname_validation.py
+@@ -0,0 +1,60 @@
++#!/usr/bin/env python3
++"""Tests for hostname validation — no FUSE mount required."""
++
++if __name__ == "__main__":
++    import pytest
++    import sys
++
++    sys.exit(pytest.main([__file__] + sys.argv[1:]))
++
++import subprocess
++from util import base_cmdline, basename
++from os.path import join as pjoin
++
++
++def test_reject_option_injection_in_hostname(tmpdir):
++    """Bracketed source that resolves to a dash-prefixed host must be 
rejected."""
++
++    mnt_dir = str(tmpdir.mkdir("mnt"))
++    malicious = "[-oProxyCommand=echo pwned]:/path"
++
++    cmdline = base_cmdline + [
++        pjoin(basename, "sshfs"),
++        "-f",
++        malicious,
++        mnt_dir,
++    ]
++    res = subprocess.run(
++        cmdline,
++        stdin=subprocess.DEVNULL,
++        stdout=subprocess.PIPE,
++        stderr=subprocess.PIPE,
++        timeout=10,
++        text=True,
++    )
++    assert res.returncode != 0
++    assert "invalid hostname" in res.stderr
++
++
++def test_reject_dash_host_after_doubledash(tmpdir):
++    """Non-bracketed dash-prefixed source after -- must also be rejected."""
++
++    mnt_dir = str(tmpdir.mkdir("mnt"))
++
++    cmdline = base_cmdline + [
++        pjoin(basename, "sshfs"),
++        "-f",
++        "--",
++        "-oProxyCommand=echo pwned:/path",
++        mnt_dir,
++    ]
++    res = subprocess.run(
++        cmdline,
++        stdin=subprocess.DEVNULL,
++        stdout=subprocess.PIPE,
++        stderr=subprocess.PIPE,
++        timeout=10,
++        text=True,
++    )
++    assert res.returncode != 0
++    assert "invalid hostname" in res.stderr
+-- 
+2.53.0
+
diff -Nru sshfs-fuse-3.7.3/debian/patches/series 
sshfs-fuse-3.7.3/debian/patches/series
--- sshfs-fuse-3.7.3/debian/patches/series      2019-11-16 03:27:57.000000000 
+0100
+++ sshfs-fuse-3.7.3/debian/patches/series      2026-06-02 13:12:58.000000000 
+0200
@@ -1 +1,3 @@
 #sshfs.1.patch
+add-contain_symlinks-option-to-prevent-symlink-escap.patch
+reject-hostname-option-injection-via-bracketed-mount.patch

--- End Message ---
--- Begin Message ---
Version: 12.15

This update was released as part of 12.15.

--- End Message ---

Reply via email to