TIL ·
ldd may run the binary you are inspecting
ldd is not a parser. It is a shell script that asks the dynamic loader to trace itself — normally by running the loader with --list, and in some versions and some situations by setting LD_TRACE_LOADED_OBJECTS=1 and executing the file itself. Whatever the loader or the file does on the way there happens with your privileges: constructors, LD_AUDIT and LD_PRELOAD handlers, or the entire program. ldd(1) states the rule plainly — never use it on an untrusted executable, because it may result in the execution of arbitrary code — and adds that upstream ldd did precisely that direct-exec trick before glibc 2.27, though most distributions shipped a version that did not.
The library list is already in the file. Read it:
objdump -p ./downloaded | grep NEEDED # what the man page recommendsThe same metadata, with the context you usually want next to it — RUNPATH, RPATH, SONAME, and the symbol versions a binary insists on:
readelf -d ./downloaded
patchelf --print-needed ./downloaded
patchelf --print-interpreter ./downloaded # the PT_INTERP loader the file expectsTwo caveats the manual page flags alongside its own recommendation. NEEDED lists direct dependencies only, where ldd prints the whole resolved tree; and a statically linked binary has no NEEDED entries at all, which is itself the answer if you are checking whether something carries its own libc.
Turning sonames into paths does not require running anything. Ask the loader cache:
ldconfig -p | grep -F 'libssl.so.3'For the full tree, lddtree from pax-utils walks the dependencies by reading ELF files on disk and explicitly never executes or loads the code:
lddtree ./downloadedThat answers “what does this need”. If the question is what it does while loading, no static tool will answer it, and the answer is to run it somewhere it cannot reach:
unshare --user --map-root-user --net --mount ./downloadedAn empty network namespace and a private mount table contain most of the damage, but that is blast-radius reduction, not a sandbox. Against code you genuinely distrust, use a throwaway VM. Against code you ship, ldd is fine and still the friendliest tool — the objection is only ever about trust.