There's a similar question that deals with the 'wrapping' scenario, where you want to replace for example cd with a command that calls the builtin cd.However, in light of shellshock et al and knowing that bash imports functions from the environment, I've done a few tests and I can't find a way to safely call the builtin cd from my script.Consider thiscd() { echo muahaha; }export -f cdAny scripts called in this environment using cd will break (consider the effects of something like cd dir && rm -rf .).There are commands to check the type of a command (conveniently called type) and commands for executing the builtin version rather than a function (builtin and command). But, lo and behold, these can be overridden using functions as wellbuiltin() { $@; }command() { $@; }type() { echo $1 is a shell builtin; }Will yield the following:$ type cdcd is a shell builtin$ cd xmuahaha$ builtin cd xmuahaha$ command cd xmuahahaIs there any way to safely force bash to use the builtin command, or at least detect that a command isn't a builtin, without clearing the entire environment?I realize if someone controls your environment you're probably screwed anyway, but at least for aliases you've got the option to not call the alias by inserting a \ before it.
How do I explicitly and safely force the use of a built-in command in bash
bash;security
Olivier D is almost correct, but you must set POSIXLY_CORRECT=1 before running unset. POSIX has a notion of Special Built-ins, and bash supports this. unset is one such builtin. Search for SPECIAL_BUILTIN in builtins/*.c in the bash source for a list, it includes set, unset, export, eval and source.$ unset() { echo muahaha-unset; }$ unset unsetmuahaha-unset$ POSIXLY_CORRECT=1$ unset unsetThe rogue unset has now been removed from the environment, if you unset command, type, builtin then you should be able to proceed, but unset POSIXLY_CORRECT if you are relying on non-POSIX behaviour or advanced bash features.This does not address aliases though, so you must use \unset to be sure it works in interactive shell (or always, in case expand_aliases is in effect).For the paranoid, this should fix everything, I think:POSIXLY_CORRECT=1\unset -f help read unset\unset POSIXLY_CORRECTre='^([a-z:.\[]+):' # =~ is troublesome to escapewhile \read cmd; do     [[ $cmd =~ $re ]] && \unset -f ${BASH_REMATCH[1]}; done < <( \help -s * )(while, do, done and [[ are reserved words and don't need precautions.)Note we are using unset -f to be sure to unset functions, although variables and functions share the same namespace it's possible for both to exist simultaneously (thanks to Etan Reisner) in which case unset-ing twice would also do the trick. You can mark a function readonly, bash does not prevent you unsetting a readonly function up to and including bash-4.2, bash-4.3 does prevent you but it still honours the special builtins when POSIXLY_CORRECT is set.A readonly POSIXLY_CORRECT is not a real problem, this is not a boolean or flag its presence enables POSIX mode, so if it exists as a readonly you can rely on POSIX features, even if the value is empty or 0. You'll simply need to unset problematic functions a different way than above, perhaps with some cut-and-paste:\help -s * | while IFS=:  read cmd junk; do echo \\unset -f $cmd; done(and ignore any errors) or engage in some other scriptobatics.Other notes:function is a reserved word, it can be aliased but not overridden with a function. (Aliasing function is mildly troublesome because \function is not acceptable as a way of bypassing it)[[, ]] are reserved words, they can be aliased (which will be ignored) but not overridden with a function (though functions can be so named)(( is not a valid name for a function, nor an alias