VYPR
Medium severity6.5NVD Advisory· Published May 20, 2026· Updated May 20, 2026

CVE-2026-43620

CVE-2026-43620

Description

Rsync version 3.4.2 and prior contain a receiver-side out-of-bounds array read vulnerability in recv_files() in receiver.c that allows a malicious rsync server to crash the rsync client process. Attackers can exploit the vulnerability by setting CF_INC_RECURSE in compatibility flags and sending a specially crafted file list where the first sorted entry is not the leading dot directory, followed by a transfer record with ndx=0 and an iflag word without ITEM_TRANSFER, causing the receiver to read 8 bytes before the allocated pointer array and dereference an invalid pointer at an unmapped address, resulting in a deterministic SIGSEGV crash of the rsync client.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A malicious rsync server can crash any client running rsync ≤3.4.2 by sending a crafted file list and transfer record, causing a deterministic out-of-bounds read and SIGSEGV.

Vulnerability

An out-of-bounds array read vulnerability exists in recv_files() in receiver.c of rsync versions 3.4.2 and prior. The bug is triggered when an attacker-controlled server sets CF_INC_RECURSE in the compatibility flags and sends a specially crafted file list where the first sorted entry is not the leading dot directory. The server then sends a transfer record with ndx=0 and an iflag word that does not include ITEM_TRANSFER (e.g., ITEM_IS_NEW). This causes the receiver to evaluate dir_flist->files[cur_flist->parent_ndx] with parent_ndx == -1, reading 8 bytes before the allocated pointer array. The dereference of the resulting invalid pointer leads to a deterministic crash [1][3].

Exploitation

An attacker needs to operate a malicious rsync server that the victim client connects to, either via rsync:// URL or remote-shell (rsync user@host:path/). No special client options are required; the inc_recurse flag is the default for protocol 30+. The attacker sends a malformed file list and transfer record as described, causing the client to read out-of-bounds and dereference an unmapped address, resulting in a SIGSEGV crash [1].

Impact

Successful exploitation results in a deterministic denial of service (DoS) of the rsync client process. The out-of-bounds read targets kernel-managed mmap chunk metadata, not attacker-controllable heap data, so the crash is limited to segfault and cannot be leveraged for code execution or information disclosure on glibc x86-64 Linux [1].

Mitigation

The vulnerability is fixed in rsync version 3.4.3, released on the same day as the advisory [2]. Users should upgrade to 3.4.3 or later. No workaround is available; pulling from untrusted rsync servers should be avoided until the patch is applied [1][2].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

6
a0b9a8e989f6

NEWS: prepare 3.4.3 release entry with six CVEs

https://github.com/rsyncproject/rsyncAndrew TridgellMay 7, 2026Fixed in 3.4.3via llm-release-walk
1 file changed · +140 6
  • NEWS.md+140 6 modified
    @@ -1,7 +1,122 @@
    -# NEWS for rsync 3.4.3 (UNRELEASED)
    +# NEWS for rsync 3.4.3 (20 May 2026)
     
     ## Changes in this version:
     
    +### SECURITY FIXES:
    +
    +Six CVEs are fixed in this release.  All six are assigned by
    +VulnCheck as CNA.  Affected versions are 3.4.2 and earlier in every
    +case.  Three of the six (CVE-2026-29518, CVE-2026-43617,
    +CVE-2026-43619) require non-default daemon configuration to reach:
    +the first and third need `use chroot = no` for a module, the second
    +needs `daemon chroot = ...` set in rsyncd.conf.  Two (CVE-2026-43618,
    +CVE-2026-43620) are reachable from a normal pull or a normal
    +authenticated daemon connection.  The sixth (CVE-2026-45232) is
    +reachable only when `RSYNC_PROXY` is set and the proxy (or a MITM)
    +returns a pathological response.  Many thanks to the external
    +researchers who reported these issues.
    +
    +- CVE-2026-29518 (CVSS v4.0 7.3, HIGH): TOCTOU symlink race condition
    +  allowing local privilege escalation in daemon mode without chroot.
    +  An rsync daemon configured with "use chroot = no" was exposed to a
    +  time-of-check / time-of-use race on parent path components: a local
    +  attacker with write access to a module could replace a parent
    +  directory component with a symlink between the receiver's check and
    +  its open(), redirecting reads (basis-file disclosure) and writes
    +  (file overwrite) outside the module.  Default "use chroot = yes" is
    +  not exposed.  `secure_relative_open()` (added in 3.4.0 for
    +  CVE-2024-12086) was previously unused in the daemon-no-chroot
    +  case; the fix enables it there and reroutes the sender's
    +  read-path opens through it.  Reported by Nullx3D (Batuhan Sancak),
    +  Damien Neil and Michael Stapelberg.
    +
    +- CVE-2026-43617 (CVSS v3.1 4.8, MEDIUM): Hostname/ACL bypass on an
    +  rsync daemon configured with `daemon chroot = /X` in rsyncd.conf
    +  when the chroot tree lacks DNS resolution support.  The
    +  reverse-DNS lookup of the connecting client was performed *after*
    +  the daemon chroot had been entered; if /X did not contain the
    +  libc resolver fixtures (`/etc/resolv.conf`, `/etc/nsswitch.conf`,
    +  `/etc/hosts`, NSS service modules) the lookup failed and the
    +  connecting hostname was set to "UNKNOWN", causing hostname-based
    +  deny rules to silently fail open.  IP-based ACLs are unaffected.
    +  The per-module `use chroot` setting is unrelated to this issue.
    +  The fix performs the lookup before entering the daemon chroot.
    +  Reported by MegaManSec.
    +
    +- CVE-2026-43618 (CVSS v3.1 8.1, HIGH): Integer overflow in the
    +  compressed-token decoder enabling remote memory disclosure to an
    +  authenticated daemon peer.  The receiver accumulated a 32-bit
    +  signed counter without overflow checking; a malicious sender could
    +  trigger an overflow that, with careful manipulation, leaked process
    +  memory contents to the attacker -- environment variables,
    +  passwords, heap and library pointers -- significantly weakening
    +  ASLR.  The fix bounds the counter and adds wire-input validation in
    +  several adjacent places (defence-in-depth).  Workaround for older
    +  releases: `refuse options = compress` in rsyncd.conf.  Reported by
    +  Omar Elsayed.
    +
    +- CVE-2026-43619 (CVSS v3.1 6.3, MEDIUM): Symlink races on path-based
    +  system calls in "use chroot = no" daemon mode (generalisation of
    +  CVE-2026-29518).  Earlier fixes for symlink races on the receiver's
    +  open() call missed the same race class on every other path-based
    +  system call: chmod, lchown, utimes, rename, unlink, mkdir, symlink,
    +  mknod, link, rmdir and lstat.  The fix routes each affected
    +  path-based syscall through a parent dirfd opened under
    +  RESOLVE_BENEATH-equivalent kernel-enforced confinement (openat2 on
    +  Linux 5.6+, O_RESOLVE_BENEATH on FreeBSD 13+ and macOS 15+,
    +  per-component O_NOFOLLOW walk elsewhere).  Default "use chroot =
    +  yes" is not exposed.  Reported by Andrew Tridgell as a follow-on
    +  audit of CVE-2026-29518.
    +
    +- CVE-2026-43620 (CVSS v3.1 6.5, MEDIUM): Out-of-bounds read in the
    +  receiver's recv_files() enabling remote denial-of-service of any
    +  client pulling from a malicious server (incomplete fix of commit
    +  797e17f).  The earlier parent_ndx<0 guard added to send_files() was
    +  not applied to the visually-identical block in recv_files().  A
    +  malicious rsync server can drive any connecting client into a
    +  deterministic SIGSEGV by setting CF_INC_RECURSE in the
    +  compatibility flags and sending a crafted file list and transfer
    +  record.  inc_recurse is the protocol-30+ default, so no special
    +  options are required on the victim.  Workaround for older
    +  releases: `--no-inc-recursive` on the client.  Reported by Pratham
    +  Gupta.
    +
    +- CVE-2026-45232 (CVSS v3.1 3.1, LOW): Off-by-one out-of-bounds stack
    +  write in the rsync client's HTTP CONNECT proxy handler
    +  (`establish_proxy_connection()` in `socket.c`).  After issuing the
    +  CONNECT request, rsync read the proxy's first response line one
    +  byte at a time into a 1024-byte stack buffer with the bound
    +  `cp < &buffer[sizeof buffer - 1]`.  If the proxy (or a MITM in
    +  front of it) returned 1023+ bytes on that first line without a
    +  newline terminator, `cp` exited the loop pointing at a buffer slot
    +  the loop never wrote, leaving `*cp` holding stale stack data from
    +  the earlier `snprintf()` of the outgoing CONNECT request.  The
    +  post-loop logic then wrote a single `\0` one byte past the end of
    +  the buffer on the stack.  Reach is client-side only, and only when
    +  `RSYNC_PROXY` is set so rsync tunnels an `rsync://` connection
    +  through an HTTP CONNECT proxy.  The written byte is always `\0`
    +  and the offset is fixed by the buffer size, not attacker-chosen,
    +  so this is not an arbitrary-write primitive: practical impact is
    +  corruption of one adjacent stack byte and possible later
    +  misbehaviour or crash.  The fix detects the "buffer filled without
    +  finding `\n`" case explicitly by position and refuses the response
    +  with "proxy response line too long".  Reported by Aisle Research
    +  via Michal Ruprich (rsync-3.4.1-2.el10 QE).
    +
    +In addition to the six CVE fixes, this release adds defence-in-depth
    +hardening on several adjacent paths: bounded wire-supplied counts and
    +lengths in flist/io/acls/xattrs, a guard against length underflow in
    +cumulative `snprintf()` callers, a parent block-index bounds check on
    +the receiver, a NULL check in `read_delay_line()`, a lower ceiling on
    +`MAX_WIRE_DEL_STAT` to avoid signed-int overflow in the
    +`read_del_stats()` accumulator, rejection of hyphen-prefixed
    +remote-shell hostnames (defence-in-depth against argv-injection in
    +tooling that forwards untrusted input into the hostspec position;
    +reported by Aisle Research via Michal Ruprich), and a NULL-check on
    +`localtime_r()` in `timestring()` to keep a malicious server from
    +crashing the client by advertising a file with an out-of-range
    +modtime.
    +
     ### BUG FIXES:
     
     - Fixed a regression introduced by the 3.4.0 secure_relative_open()
    @@ -37,14 +152,33 @@
       with protocol < 29, top-level files). The test skips on
       platforms without a RESOLVE_BENEATH equivalent.
     
    -- runtests.py now errors early with a clear message when the test
    -  helper programs (`tls`, `trimslash`, `t_unsafe`, `wildtest`,
    -  `getgroups`, `getfsdev`) are missing, instead of letting many
    -  tests fail with confusing "not found" errors.
    +- Added regression tests for the new security fixes:
    +  `chmod-symlink-race.test`, `chdir-symlink-race.test`,
    +  `bare-do-open-symlink-race.test`, `alt-dest-symlink-race.test`,
    +  `copy-dest-source-symlink.test`, `sender-flist-symlink-leak.test`,
    +  `secure-relpath-validation.test`, `daemon-chroot-acl.test` and
    +  `daemon-refuse-compress.test`. The symlink-race tests skip on
    +  Cygwin, Solaris, OpenBSD and NetBSD (no RESOLVE_BENEATH
    +  equivalent on those platforms).
    +
    +- runtests.py now errors early with a clear message when any of
    +  the test helper programs (`tls`, `trimslash`, `t_unsafe`,
    +  `t_chmod_secure`, `t_secure_relpath`, `wildtest`, `getgroups`,
    +  `getfsdev`) are missing, instead of letting many tests fail with
    +  confusing "not found" errors.
     
     - Added OpenBSD and NetBSD CI jobs that run `make check` on those
       platforms.
     
    +- Added Ubuntu 22.04 and AlmaLinux 8 CI workflows so future
    +  backports to the two mainstream LTS families build and test on
    +  the same CI surface as trunk.
    +
    +- testsuite/protected-regular.test now runs unprivileged via
    +  `unshare` with user-namespace UID mapping, falling back to skip
    +  if `unshare`/`uidmap` is not available; previously it required
    +  real root.
    +
     - Added `symlink-dirlink-basis` to the Cygwin CI's expected-skipped
       list.
     
    @@ -5035,7 +5169,7 @@ to develop and test fixes.
     
     | RELEASE DATE | VER.   | DATE OF COMMIT\* | PROTOCOL    |
     |--------------|--------|------------------|-------------|
    -| ?? ??? 2026  | 3.4.3  |                  | 32          |
    +| 20 May 2026  | 3.4.3  |                  | 32          |
     | 28 Apr 2026  | 3.4.2  |                  | 32          |
     | 16 Jan 2025  | 3.4.1  |                  | 32          |
     | 15 Jan 2025  | 3.4.0  | 15 Jan 2025      | 32          |
    
0cf200ecbb8b

receiver: add parent_ndx<0 guard, mirroring 797e17f

https://github.com/rsyncproject/rsyncAndrew TridgellMay 5, 2026Fixed in 3.4.3via llm-release-walk
4 files changed · +15 1
  • generator.c+4 0 modified
    @@ -2146,6 +2146,8 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
     			if (send_failed)
     				ndx = get_hlink_num();
     			flist = flist_for_ndx(ndx, "check_for_finished_files.1");
    +			if (ndx < flist->ndx_start)
    +				exit_cleanup(RERR_PROTOCOL);
     			file = flist->files[ndx - flist->ndx_start];
     			assert(file->flags & FLAG_HLINKED);
     			if (send_failed)
    @@ -2174,6 +2176,8 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
     
     			flist = cur_flist;
     			cur_flist = flist_for_ndx(ndx, "check_for_finished_files.2");
    +			if (ndx < cur_flist->ndx_start)
    +				exit_cleanup(RERR_PROTOCOL);
     
     			file = cur_flist->files[ndx - cur_flist->ndx_start];
     			if (solo_file)
    
  • io.c+3 0 modified
    @@ -1090,6 +1090,9 @@ static void got_flist_entry_status(enum festatus status, int ndx)
     {
     	struct file_list *flist = flist_for_ndx(ndx, "got_flist_entry_status");
     
    +	if (ndx < flist->ndx_start)
    +		exit_cleanup(RERR_PROTOCOL);
    +
     	if (remove_source_files) {
     		active_filecnt--;
     		active_bytecnt -= F_LENGTH(flist->files[ndx - flist->ndx_start]);
    
  • receiver.c+6 1 modified
    @@ -467,7 +467,10 @@ static void handle_delayed_updates(char *local_name)
     static void no_batched_update(int ndx, BOOL is_redo)
     {
     	struct file_list *flist = flist_for_ndx(ndx, "no_batched_update");
    -	struct file_struct *file = flist->files[ndx - flist->ndx_start];
    +	struct file_struct *file;
    +	if (ndx < flist->ndx_start)
    +		exit_cleanup(RERR_PROTOCOL);
    +	file = flist->files[ndx - flist->ndx_start];
     
     	rprintf(FERROR_XFER, "(No batched update for%s \"%s\")\n",
     		is_redo ? " resend of" : "", f_name(file, NULL));
    @@ -604,6 +607,8 @@ int recv_files(int f_in, int f_out, char *local_name)
     
     		if (ndx - cur_flist->ndx_start >= 0)
     			file = cur_flist->files[ndx - cur_flist->ndx_start];
    +		else if (cur_flist->parent_ndx < 0)
    +			exit_cleanup(RERR_PROTOCOL);
     		else
     			file = dir_flist->files[cur_flist->parent_ndx];
     		fname = local_name ? local_name : f_name(file, fbuf);
    
  • sender.c+2 0 modified
    @@ -140,6 +140,8 @@ void successful_send(int ndx)
     		return;
     
     	flist = flist_for_ndx(ndx, "successful_send");
    +	if (ndx < flist->ndx_start)
    +		exit_cleanup(RERR_PROTOCOL);
     	file = flist->files[ndx - flist->ndx_start];
     	if (!change_pathname(file, NULL, 0))
     		return;
    
0cf200ecbbba
https://github.com/rsyncproject/rsyncFixed in 3.4.3via llm-release-walk
650643109e6e

defence-in-depth: receiver block-index bounds + read_delay_line null check

https://github.com/rsyncproject/rsyncAndrew TridgellDec 31, 2025Fixed in 3.4.3via llm-release-walk
2 files changed · +15 4
  • generator.c+10 4 modified
    @@ -229,11 +229,13 @@ static int read_delay_line(char *buf, int *flags_p)
     		*flags_p = 0;
     
     	if (sscanf(bp, "%x ", &mode) != 1) {
    -	  invalid_data:
    -		rprintf(FERROR, "ERROR: invalid data in delete-delay file.\n");
    -		return -1;
    +		goto invalid_data;
    +	}
    +	past_space = strchr(bp, ' ');
    +	if (!past_space) {
    +		goto invalid_data;
     	}
    -	past_space = strchr(bp, ' ') + 1;
    +	past_space++;
     	len = j - read_pos - (past_space - bp) + 1; /* count the '\0' */
     	read_pos = j + 1;
     
    @@ -247,6 +249,10 @@ static int read_delay_line(char *buf, int *flags_p)
     	memcpy(buf, past_space, len);
     
     	return mode;
    +
    +invalid_data:
    +	rprintf(FERROR, "ERROR: invalid data in delete-delay file.\n");
    +	return -1;
     }
     
     static void do_delayed_deletions(char *delbuf)
    
  • receiver.c+5 0 modified
    @@ -352,6 +352,11 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
     		}
     
     		i = -(i+1);
    +		if (i < 0 || i >= sum.count) {
    +			rprintf(FERROR, "Invalid block index %d (count=%ld) [%s]\n",
    +				i, (long)sum.count, who_am_i());
    +			exit_cleanup(RERR_PROTOCOL);
    +		}
     		offset2 = i * (OFF_T)sum.blength;
     		len = sum.blength;
     		if (i == (int)sum.count-1 && sum.remainder != 0)
    
23d177db2a0f
https://github.com/rsyncproject/rsyncFixed in 3.4.3via llm-release-walk
27f9e1b7c8d4
https://github.com/rsyncproject/rsyncFixed in 3.4.3via llm-release-walk

Vulnerability mechanics

Root cause

"Missing bounds check when indexing into the file-list pointer array with a negative index (ndx=0 when the first sorted entry is not the leading dot directory) causes an out-of-bounds read before the allocated buffer."

Attack vector

An attacker controlling a malicious rsync server sends a specially crafted file list where the first sorted entry is not the leading dot directory, and sets CF_INC_RECURSE in the compatibility flags. The server then sends a transfer record with ndx=0 and an iflag word that lacks ITEM_TRANSFER. When the rsync client processes this record in recv_files(), it computes an index of -1 into the pointer array (file_list->files), reading 8 bytes before the allocated buffer and dereferencing an invalid pointer, causing a deterministic SIGSEGV crash. The attack requires no authentication and is triggered over the network during a standard rsync pull operation [CWE-125].

Affected code

The vulnerability resides in recv_files() in receiver.c. When CF_INC_RECURSE is set and the first sorted entry is not the leading dot directory, the code computes an index into file_list->files without ensuring the index is non-negative, allowing an access at offset -1 (8 bytes before the allocated array).

What the fix does

The patch [patch_id=798593] adds a guard in recv_files() in receiver.c to check that the computed index into the file-list pointer array is non-negative before dereferencing it. Specifically, when CF_INC_RECURSE is set and the first sorted entry is not the dot directory, the code now validates that ndx is greater than or equal to 0 before accessing file_list->files[ndx]. This closes the out-of-bounds read by rejecting the malformed transfer record that would otherwise cause an access at index -1 [CWE-125].

Preconditions

  • networkAttacker must operate a malicious rsync server reachable by the victim client
  • inputServer sends a crafted file list where the first sorted entry is not the leading dot directory
  • inputServer sets CF_INC_RECURSE in compatibility flags
  • inputServer sends a transfer record with ndx=0 and an iflag word without ITEM_TRANSFER

Generated on May 20, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

3

News mentions

0

No linked articles in our index yet.