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
