Hi Michal,

On 4/27/26 08:50, Michał Majchrowicz wrote:
Wiadomość napisana przez Bernhard Voelker <[email protected]> w dniu 26 
kwi 2026, o godz. 22:38:
On 4/26/26 14:25, Michał Majchrowicz wrote:
Hello,
We would like to report a security vulnerability in GNU findutils that allows
arbitrary command execution through environment variable injection in the
updatedb script.
=================================================================
SUMMARY
=================================================================
Product:    GNU findutils
Component:  locate/updatedb.sh  (installed as <prefix>/sbin/updatedb)
Commit:     34929da6 (current HEAD at time of discovery)
Type:       OS Command Injection
CWE:        CWE-78: Improper Neutralization of Special Elements
            used in an OS Command ('OS Command Injection')
Affected:   All versions shipping the current updatedb.sh
=================================================================
VULNERABILITY DETAILS
=================================================================
The updatedb script exposes two internal variables — `find` and `frcode` —
that users can override via environment variables. These variables hold paths
to the `find` and `frcode` binaries that updatedb invokes internally.
The script validates each binary path with the helper function checkbinary():
    checkbinary () {
        if test -x "$1" ; then
            : ok
        else
          eval echo "updatedb needs to be able to execute $1, but cannot." >&2
          exit 1
        fi
    }
    for binary in $find $frcode
    do
      checkbinary $binary
    done
Two weaknesses combine to allow command injection:
  1. The loop `for binary in $find $frcode` is unquoted. When $find contains
     backtick sequences, they survive word-splitting as a single token and
     are passed as the argument $1 to checkbinary().
  2. Inside checkbinary(), the call to `eval echo "...execute $1..."` causes
     the shell to re-parse the double-quoted string. Backtick command
     substitutions embedded in $1 are executed by the `eval` at this point.
The `eval` here is entirely unnecessary: the function is only printing an
error message and no shell word-expansion of the message text is required.
=================================================================
AFFECTED CODE
=================================================================
File: locate/updatedb.sh
  Line 217-218 (environment variable overrides):
    : ${find:=${BINDIR}/@find@}
    : ${frcode:=${LIBEXECDIR}/@frcode@}
  Line 241-248 (checkbinary — vulnerable function):
    checkbinary () {
        if test -x "$1" ; then
            : ok
        else
          eval echo "updatedb needs to be able to execute $1, but cannot." >&2
          exit 1
        fi
    }
  Line 250-253 (invocation — unquoted variables):
    for binary in $find $frcode
    do
      checkbinary $binary
    done
=================================================================
EXPLOITATION STEPS
=================================================================
Prerequisites: the attacker can set environment variables visible to the
updatedb process (e.g. a misconfigured cron job, a SUID wrapper, or a
local user on a shared system).
Step 1:  Identify the path to the updatedb binary:
           which updatedb   # typically /usr/sbin/updatedb or /usr/bin/updatedb
Step 2:  Craft a payload.  The token must contain no whitespace so that it
         survives the unquoted word-split in the `for` loop.  Any shell
         command without spaces is usable.  Examples:
           find='`touch /tmp/PWNED`x'
           find='`id>/tmp/id.txt`x'
         The trailing `x` makes the full token a non-existent path, ensuring
         that test -x "$1" returns false and the eval branch is reached.
Step 3:  Run updatedb with the malicious variable set:
           find='`touch /tmp/PWNED`x' frcode='x' bash /path/to/updatedb 2>&1
Step 4:  Execution trace:
           a) ${find:=...}  is skipped because find is already set
           b) for binary in $find  →  binary = `touch /tmp/PWNED`x
           c) checkbinary $binary  →  $1 = `touch /tmp/PWNED`x
           d) test -x "`touch /tmp/PWNED`x"  →  returns false (path absent)
           e) eval echo "...execute `touch /tmp/PWNED`x..."
              →  shell expands backtick → touch is executed → /tmp/PWNED created
=================================================================
REPRODUCTION
=================================================================
The following commands reproduce the issue on a clean build of the
current HEAD on an x86_64 Linux system.
  # Build from source (standard steps)
  git clone https://git.savannah.gnu.org/git/findutils.git
  cd findutils
  ./bootstrap
  ./configure
  make
  # Remove any previous evidence
  rm -f /tmp/PWNED
  # Run the exploit
  find='`touch /tmp/PWNED`x' frcode='x' bash locate/updatedb 2>&1
  # Confirm command execution
  ls -la /tmp/PWNED
Expected output: /tmp/PWNED exists, confirming that the `touch` command
inside the backtick sequence was executed by eval.
=================================================================
SUGGESTED FIX
=================================================================
Remove the `eval` keyword from checkbinary().  It serves no purpose beyond
enabling the injection — the function only needs to print a plain string:
  Before:
    eval echo "updatedb needs to be able to execute $1, but cannot." >&2
  After:
    echo "updatedb needs to be able to execute $1, but cannot." >&2
This one-character change eliminates the injection vector entirely.
The message text is printed verbatim without any shell re-parsing.
After applying the patch above and re-running the exploit,the command
inside the backtick sequence is no longer executed and /tmp/PWNED
is not created.  The script still prints the expected error:
  updatedb needs to be able to execute `touch /tmp/PWNED`x, but cannot.
=================================================================
CREDITS
=================================================================
This issue was identified by Michał Majchrowicz and Marcin Wyczechowski,
members of the AFINE Team.
=================================================================
DISCLOSURE POLICY
=================================================================
We follow a 90-day coordinated disclosure policy.  We will publish the
details of this vulnerability 90 days after the date of this report,
or earlier if a fix is released publicly before that deadline.
We are happy to coordinate the disclosure timeline with you and to delay
publication if a fix is imminent.
Please let us know if you have any questions or require additional information.
Regards,
—
*Michał Majchrowicz* / Offensive Security Engineer / PhD eWPTX
PGP: D52A 5289 8256 006D 5E05 BAC6 *79EA 0072 F4E1 9D57*
*AFINE sp. z o.o.*
Al. Jerozolimskie 146C, 02-305 Warszawa
https://www.afine.com <https://www.afine.com>
<0001-updatedb-properly-quote-variables-and-avoid-redundan.patch>

>>
>> Hi Michal,
>>
>> thanks for the report.
>>
>> Indeed, the non-quoting and the use of eval is quite weak in updatedb.
>> The whole handling of the variables like $NETPATHS, $FINDOPTIONS and 
$print_option gives me goosebumps.
>> I'll fix at least the ones you reported with the attached patch.
>>
>> FWIW, trying the reproducer leads to a shell syntax error:
>>
>>  $ find='`touch /tmp/PWNED`x' frcode='x' bash locate/updatedb
>>  locate/updatedb: eval: line 245: unexpected EOF while looking for matching 
``'
>>
>> ... instead of the creation of the /tmp/PWNED witness file.
>>
>> Have a nice day,
>> Berny
>>
> Hello Bernhard,
> Yes you are right it won’t work as a manual command (I was testing from a 
script) as earlier
> for iterates over all white spaces. You can reproduce it manually using this 
cmd:
> find='`id>/tmp/PWNED_eval_injection`x' frcode='x' bash ./locate/updatedb 2>&1
> Your patch also correctly fixes the issue.
> Regards,

Thanks for the review, pushed at:
  https://cgit.git.savannah.gnu.org/cgit/findutils.git/commit/?id=722c98ed390f

Have a nice day,
Berny
From 722c98ed390f645606acb173f1664154d5e108c7 Mon Sep 17 00:00:00 2001
From: Bernhard Voelker <[email protected]>
Date: Sun, 26 Apr 2026 22:24:39 +0200
Subject: [PATCH] updatedb: properly quote variables and avoid redundant eval
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* locate/updatedb.sh (checkbinary): Remove 'eval' before echo which serves
no purpose here, but instead open an attack surface if the given binary
contains dangerously crafted content.
Add proper quotes in the caller loop as well.
* NEWS: Mention the fix.

Reported by Michał Majchrowicz <[email protected]>.
---
 NEWS               | 3 +++
 locate/updatedb.sh | 6 +++---
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS
index 258517dc..cffd084f 100644
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,9 @@ GNU findutils NEWS - User visible changes.      -*- outline -*- (allout)
   already states this, and now find's behaviour matches the
   documentation.
 
+  'updatedb.sh' now properly handles the variables for the 'find' and 'frcode'
+  utilities, and hence avoids command injection.
+
 ** Changes in find
 
   As announced since the release of 4.7.0 (2019) and mandated by POSIX 2024,
diff --git a/locate/updatedb.sh b/locate/updatedb.sh
index 8af91204..4014a4bf 100644
--- a/locate/updatedb.sh
+++ b/locate/updatedb.sh
@@ -242,14 +242,14 @@ checkbinary () {
     if test -x "$1" ; then
 	: ok
     else
-      eval echo "updatedb needs to be able to execute $1, but cannot." >&2
+      echo "updatedb needs to be able to execute '$1', but cannot." >&2
       exit 1
     fi
 }
 
-for binary in $find $frcode
+for binary in "$find" "$frcode"
 do
-  checkbinary $binary
+  checkbinary "$binary"
 done
 
 
-- 
2.54.0

  • Re: [Securi... Bernhard Voelker
    • Re: [S... Michał Majchrowicz via Bug reports for the GNU find utilities

Reply via email to