Hacker Newsnew | past | comments | ask | show | jobs | submit | mathfailure's commentslogin

Not if if you APPEND the dot path to the PATH env: the system traverses the dirs specified in the PATH env from left to right and stops at first match. Your system's sed binary is in the dir that's to the left of your '.' dir.

Appending is much better than prefixing, but having "." in the path, anywhere, can still open you up to running mistyped commands (arguably a much less common possibility, but still a possibility).

I.e., you have "." as the very last item in your path. You are in /tmp/ (so a directory other uses can write files to). You mean to type "ls -l something" to look for "something" files. But instead, you just miss the space, and type "ls-l something*", and some other nefarious user has left a /tmp/ls-l binary behind just waiting to be run. It could package up your ~/.ssh folder and ship it off to "nefarious" user, and then do a proper "ls -l" so that you may not even notice the typo.

And, if you happen to be root when you are in /tmp and mistype ls-l, and if the ls-l binary checks to see if it is being run as root, it could then do even worse. For example, it could leave behind an suid to root bash or sh executable in 'nefarious user's' home dir, so that 'nefarious' can now become root at some point later and proceed to actually 'own' the system.


Right, that's one way to be half-smart about it. But you have to make sure that's the final thing you append to the path. An easy mistake to make is temporal. You add `.` to the path, and time passes, someone appends `/opt/bin` to the path, and time passes, someone writes `~/not-in-path/defaulted/busybox` that references `/opt/bin/busybox` as just `busybox` and tests it by running `~/not-in-path/defaulted/busybox` while being in `~` and it works so they leave it alone, then you go `cd ~/not-in-path/defaulted/` and run it and die.

"I don't understand. I very specifically appended `.` at the end!"

Of course you can stick a comment "#the following should always be at the end of the file" or whatever or say "we should always make sure to reference binaries by their full path, so always write out `/opt/bin/busybox` rather than just `busybox`" and stuff like that. With enough system you can make this unlikely.


> if you end up in a directory that's not under your control, and you do a "ls", it might execute "./ls" instead of /usr/bin/ls,

Not if if you APPEND the dot path to the PATH env: the system traverses the dirs specified in the PATH env from left to right and stops at first match. Your system's ls binary is in the dir that's to the left of your '.' dir.


Yeah, there are ways to reduce the impact (as a sibling comment mentioned, typos or commands missing on a system could still be used to trick the operator), but I was mostly explaining the attack vector in case it is present in the PATH.

Then it's a little bit of a stretch but they could put a script with the name of a common typo similar to commonly run commands there. Maybe "ls-l" without the space in case they miss the space. Yeah, that's a stretch. I went looking for better sources.

> The current directory ( . ) is not in PATH by default, for security reasons. This prevents accidentally running unintended programs in your current directory.

-- POSIX Shell scripting from scratch, By Sultan Zavrak (states it in general terms. They also use ls as an example though, which shouldn't be affected if you have "." at the end.)

Practical UNIX and Internet Security has an example of "." (or having a null entry in the PATH, which also indicates the current directory; I didn't know that![0]) at the beginning, which is obviously a bad idea, but he (Simson Garfinkel) makes a good point:

> More generally, you should never have a path that is writable by other users.

Ah yes, finally, he covers a situation where you have a directory at the end of your path, that is writable by others ("." would count) and having a trojan named "mroe" (for "more") waiting patiently for the superuser to mess up.

He even goes so far to say that root should run commands with full paths, such as /sbin/chown and not just chown. I've never gone that far, except I can see the benefit of doing that in scripts.

So anyway, besides the typo example, there's also a kind of shadowing: let's say you expect a command to fail because the program is not installed. Or maybe you try to run a command you think is installed but it's not. You might even have a command or way of working that tries various commands until one works. If you have a path that someone can write to (including ".") then instead of failing, it will run something unintended, if they have shadowed that command in that directory.

[0] to quote the bash man page: A zero-length (null) directory name in the value of PATH indicates the current directory. A null directory name may appear as two adjacent colons, or as an initial or trailing colon.


Kinda makes no sense to me: so you don't use '--' as a prefix, you use it in the middle of an alias, so you first have to autocomplete, say, 'gi' not to 'git' but to 'git--progress'. What does that alias do? Doesn't it call git with some args? If so - why not just alias it to git?

> I prefer giving scripts numbers instead of names

> Something like "[number"

> It contains 100s of short scripts

So you call scripts like [1 [2 [3 [4 ... and remember what each one of them does? If yes - that's nuts, I'd visit a doctor.


Thank you

"..., I'd visit a doctor"

But I'm not you


People tend to want some separation between what's theirs and what's others. Other programs/scripts quite often put something into ~/.local/bin, so it's not yours actually, it's theirs.

Ah, I see you're a man of culture as well!

I like to follow my own convention where I name files with shell scripts with an extension: .sh for POSIX-compatible scripts, .bash for scripts with bashisms or .zsh for scripts with zshisms.

If I ever wanted to achieve what you initially wanted to achieve - I could use something like

alias -s sh=sh

alias -s bash=bash

alias -s zsh=zsh

Just like I do bind .txt and .conf to 'less', .pdf to 'qpdf', .json to 'ijq', video formats to 'mpv' and so on.


I didn't like the idea. I prefer the alternative approach: _I_ decide the order of dirs in the PATH env. If I introduce an executable with a name, that overrides a system one - I probably do that intentionally.

If I introduce an alias (like `grep='grep --binary-files=without-match --ignore-case --color=auto`) that matches the name of a system binary - I probably do that intentionally.

And if I EVER need to call grep without my alias - I just prefix it with a backslash: \grep will search with case sensitivity and no color and will scan binaries.


Looked so backwards to me, too. However, I decided to give it a go, anyway. Now, I have some scripts and small commands which start with a comma, and it looks neat and time saving.

Yes, I can do path ordering to override usual commands. However, having a set of odd-job scripts which start with a comma gives a nice namespacing capability alongside a well narrowed-down tab-completion experience.

While it's not the neatest thing around, it works surprisingly well.

Another idea which looks useless until you start using is text expanders (i.e.: Espanso and TextExpander).


I never knew that what I've known as 'hotstrings' (since the AutoHotKey days) other sometimes also call 'text expanders'.

Love Alfred Snippets for this same text expander need.

The irony in the number of extra commas you've used in this comment...

As a non-native English speaker and writer/typer I'm not well versed in usage of commas unfortunately.

Feel free to add the required ones while reading this comment.

Sorry for the inconvenience this might create.


As a native speaker the original comment seemed completely fine, ignore them. Also, I never would never guessed that you weren't also a native English speaker.

Agreed. The commas before the sentence-ending 'too' and 'anyway' were perhaps slightly unusual, but not enough so that I even noticed them, and I don't think either is incorrect. All the rest were perfectly normal.

This is an example of the difficulty in expressing tone through text. Meant it as a passing lighthearted observational joke.

No inconvenience at all.


Haha, I actually assumed you were making a joke from the beginning, it'd be funny to think that the habit of using comma prefixed commands will make someone more likely to use commas in their sentences.

Either adding your script directory in front of the PATH, or creating `alias` that provide a full path to your script where a conflict exists, makes a whole lot more sense to me.

I've never had this collision problem yet, despite appending my script directory to the end, but I'll use either of the above solutions if that ever becomes a problem.


One rarely actually needs to shadow binaries. Some cases could indeed be covered by introducing an alias that binds the binary's name to call a different copy of that binary.

You use shadowing to fix issues where you install some software that expects you to have a sane and ~recent version of some tool like git, but you don't as your system provides that binary and unfortunately it is either not sane (not GENERALLY sane [while it could be sane for system scripts]) or not recent enough. In that case the program's function would simply fail if it would call the system's binary and you shadow the binary with your version to fix that.

> adding your script directory in front of the PATH

That's a poor advice for the scripts you call relatively frequently. Instead, (as a general approach, we aren't discussing some particular script) don't use shadowing for scripts: just pick a non-conflicting script name and append the script's dir to $PATH.


> That's a poor advice for the scripts you call relatively frequently.

Why? It protects you from someone else (cough updated packages introducing new commands cough) picking a name you already use.


Because it's useless extra typing. People try to narrow commands down to two fucking chars and you suggest to type the whole goddamn path!

Nobody suggested typing whole paths.

They did. Just not explicitly.

The only situation where you'd need to type a full path is when you have a name collision. But the suggestion to not worry about collisions with unknown system binaries also said to put the script folder first. In that situation running the script doesn't need a full path, and you won't be running the unknown system binary. So you won't be typing full paths.

Please explain the non-explicit suggestion you see, because I don't see it.

It's clear that "adding your script directory in front of the PATH" means a one time edit to .bashrc or equivalent, right? In normal use you're not typing it.


I've asked you why prepending paths to PATH instead of appending was a bad idea. How is having typing full paths has anything to do with it?

From my own aliases:

   alias curl='/opt/homebrew/opt/curl/bin/curl '
   alias rsync-copy='/opt/homebrew/bin/rsync -avz --progress -h '
   alias rsync-move='/opt/homebrew/bin/rsync -avz --progress -h --remove-source-files '
   alias rsync-synchronize='/opt/homebrew/bin/rsync -avzu --delete --progress -h '
   alias rsync-update='/opt/homebrew/bin/rsync -avzu --progress -h '
   alias vi='/opt/homebrew/bin/vim -S ~/.vimrc'
   alias vim='/opt/homebrew/bin/vim -S ~/.vimrc'
   alias wget='/opt/homebrew/bin/wget -c '
There are others with flags added. These are the ones that override the builtin MacOS versions that aren't up-to-date.

Slightly confused as to why - surely homebrew adds itself to the PATH ahead of the system utilities?

Also - surely vim auto-reads your vimrc?


I learned to deliberately declare paths pretty early on in my adventures at the CLI. I don't leave room for accidental alternative execution. It might be overkill, but it gives me a sense of security and that's why it's there. Don't worry, I probably made a terrible mistake somewhere else that completely negates my attempts at a correct shell environment.

TIL: Backslash overrides alias - wow!

Thanks, mathfailure - this genuinely improves my life!


‘command grep’ also works in several shells. A little longer but looks good in scripts etc.

  > I just prefix it with a backslash: \grep
I have an almost identical grep alias.

Word of warning, I use `\grep` quite frequently. The usage is when you are piping after grep or saving to a variable.

Illustrative example:

  $ TO_DL=$(curl "https://foo.com/releases/" \
            | grep -e "latest" \
            | head -n1 \
   )
  $ curl $TO_DL
  curl: (3) bad range in URL position XX
  https://foo.com/releases/latest.tar.gz
                           ^^^^^^
Annoyingly `--color=auto` can change the representation of the characters so when you run again there's a mismatch. I just find `\grep` easier than `grep --color=never`.

Annoying footgun, but something to be aware of in case you go down this extremely confusing rabbit hole like me. I couldn't figure it out until I decided to hexdump the string.

[Side note]: My first thought reading the article was also about how `\` basically solves the problem but they do have one advantage in that they can do `,<tab>` and get a list of all their custom commands. Personally not worth it for me but I can definitely see this being useful for some. Especially on shared systems. But getting everyone to prefix a script name seems just as unlikely as getting everyone to place programs in the right location.


most pipe-friendly commands check if stdout is attached to tty or not, and if not, they drop the extra color/formatting. so grep --color=auto shouldn't output color during pipes.

When “I” means me then this usually works for me. But when “I” becomes “we”, sometimes this goes off the rails because someone introduces a bin with breaking changes that silently fucks up projects that dev doesn’t really know about, or forgot about.

Call it the Chesterton’s Fence of ‘which’.


I do this, and routinely shadow commands with my own wrappers to do things like set environment variables.

And then there’s Claude. It deletes whatever it finds at ~/.local/bin/claude, so I have to use a shell function instead to invoke the full path to my wrapper.


You can use an alias, which takes priority over $PATH. e.g. I have this in .zhsrc to override the "claude" executable to run it in the OS sandbox:

    alias claude="sandbox-exec -f ~/agents-jail.sb ~/.local/bin/claude --dangerously-skip-permissions"

How does your sandbox ruleset look? I've been using containers on Linux but I don't have a solution for macOS.

Here's my ruleset https://gist.github.com/eugene1g/ad3ff9783396e2cf35354689cc6...

My goal is to prevent Claude from blowing up my computer by erasing things it shouldn't touch. So the philosophy of my sanboxing is "You get write access to $allowlist, and read access to everything except for $blocklist".

I'm not concerned about data exfiltration, as implementing it well in a dev tool is too difficult, so my rules are limited to blocking highly sensitive folders by name.


That's neat. I'm going to base my ruleset off of yours. I've been messing around with claude more and more lately and I need to do something.

> Here's my ruleset ...

Thank you for sharing a non-trivial working example of a sandbox-exec configuration. Having an exemplar such as what you have kindly shared is hugely beneficial for those of us looking to see what can be done with a tool such as this.


Thank you - you inspired me to open-source this work properly -> https://eugene1g.github.io/agent-safehouse/

> Thank you - you inspired me to open-source this work properly

It is both myself and the OSS community which thank you.

  Great things are done by a series of small things brought 
  together.[0]
0 - https://www.brainyquote.com/quotes/vincent_van_gogh_120866

The problem with this is that you don't know what future conflicts will be. You spend years training yourself to use your own "jq" alias and then you find yourself needing to use the "jq" program and you have to remember to prefix it with backslash every time you use it (including when you copy-and-paste a command line from a webpage), or rename your own alias and re-train yourself to use its new name.

I would recommend against overriding standard system binaries, you could break compatibility on your system with scripts that depend on those binaries. I just use an abbreviation like rg=“grep -RE”

Why are those scripts running in interactive login shells? If they are influenced by the configuration of profile, then the scripts are bad.

That’s true, but I would still call overloading system binaries bad practice. Your making yourself foot gun.

No, in fact he is correct: system scripts won't pick up your overrides configured via your shell's rc scripts.

I said he was right, but in your case you are wrong. Your shell loads thr profile script for login shells, but will load your bashrc regardless of login or not

Excluding this argument, overloading system commands is still bad practice lol. Have you ever logged into an embedded device and had a busy box environment? the behaviour of some utilities can be different from what you expect for utilities of the same name.


Any severe side effects so far? Have you set PATH up somehow so it is effect only on interactive prompt, and not in the launched processes?

Because I cannot imagine much 3rd party scripts working with random flags added to core tools


I also do this.

Random flags added to core tools are done with aliases, which do not affect the launched processes, not by shadowing them in ~/bin. Shadowing in ~/bin are for cases where a newer (compared to the system-wide version) or custom version of a tool is needed.


Not really, since if one usually does that - they probably understand the possible consequences and don't shadow whatever they like, but do it carefully.

On MacOS I shadow that way just curl and git binaries to the versions installed from homebrew and nothing has broken (yet). I know that tar on MacOS is also a weirdo that I'd rather shadow with the homebrew's gtar, but their args are different and I of course understand that there's a high probability of something in system to be bound to mac's version of tar, so here I better remember to use 'sane' tar as gtar or use an alias (instead of shadowing the binary) for tar to use gtar (because aliases are for users, not for system scripts/processes).

And on my home desktop's Debian - I don't even use shadowing of binaries at all (never needed it).

Also, I just realized: I change PATH env via my shell's rc script (~/.zshrc), so I probably could worry even less about shadowing system binaries (like tar on MacOS) possibly breaking things.


Just on your first suggestion, this also means that if a person or process can drop a file (unknown to you) into your ~/bin/ then they can wreak havoc. Eg they can override `sudo` to capture your password, or override `rm` to send your files somewhere interesting, and so on.

Btw on the second suggestion, I think there's a command named `command` that can help with that sort of thing, avoids recursive pitfalls.


That would require someone to already want to sabotage me in particular, learn my private workflows, and also have write access to my home folder. At that point, All is Lost.

Don't tell people to sacrifice agency for apocalypse insurance that doesn't work, lol


If someone can drop a file in your ~/bin, they can also edit your shell’s startup files to add their malicious command.

I think it's already game over if they have access to your home directory. They can also edit your path at that point.

While true, what you describe is very unlikely to happen and most definitely won’t happens on systems where i’m the only users.

The issue of rootless malicious command overrides is solved by typing the whole path, such as "/bin/sudo".

No, don't do that as a precaution. As others have already answered correctly - it's too late to worry about such things if a malicious agent has write access to your ${HOME} dir.

The premise of the article is the desire to avoid accidental collisions, especially from newly installed system binaries.

In such cases you might get errors like sl being both a version control system and the steam locomotive


I do the same thing, but I also have a command that shows me what functions or scripts might be shadowing other scripts

Care to share?

the sibling answer but with `-a` before command name, will display all path hits for a command.

  which <commandname>

Seemed like it was more than that, but the comment is ambiguous. I took it to mean "show me all the commands which are shadowed" not "is this command shadowed"...

nope, that just gets you the first hit, not all of them

type -a commandname


quite simple

type -a <commandname>


this. which(1) and whereis(1) are not bash, only an approximation or coincidence at best:

  $ type -a which
  which is /usr/bin/which
As a bash built-in, only the type command invokes the installed bash's code path to resolve command words:

  $ type -a type
  type is a shell builtin
  type is /usr/bin/type

  $ help type
  type: type [-afptP] name [name ...]
      Display information about command type.
    
      For each NAME, indicate how it would be interpreted if used as a
      command name.
    
      Options:
        -a  display all locations containing an executable named NAME;
            includes aliases, builtins, and functions, if and only if
            the `-p' option is not also used
        -f  suppress shell function lookup
        -P  force a PATH search for each NAME, even if it is an alias,
            builtin, or function, and returns the name of the disk file
            that would be executed
        -p  returns either the name of the disk file that would be executed,
            or nothing if `type -t NAME' would not return `file'
        -t  output a single word which is one of `alias', `keyword',
            `function', `builtin', `file' or `', if NAME is an alias,
            shell reserved word, shell function, shell builtin, disk file,
            or not found, respectively
    
      Arguments:
        NAME    Command name to be interpreted.
    
      Exit Status:
      Returns success if all of the NAMEs are found; fails if any are not found.

  $ $SHELL --version
  GNU bash, version 5.3.9(1)-release

curious if you're customizing anyway, why not use eg ripgrep?

Others have already given valid answers: grep is not ripgrep [their params don't match], so it's a bad idea to alias 'grep' to use ripgrep. But it's okay to alias 'ripgrep' (or 'rg' or whatever) to use ripgrep with some args.

repgrep's CLI options and general behavior are different from grep. I tend to use both for different things.

Not OP, but I use ripgrep and customize it with an alias as well, so it applies equally there

> If I introduce an executable with a name, that overrides a system one

... and breaks existing scripts that reference the system one, right?


Not if it is an alias.

But yes if it’s another executable.

Surely they do! The data is in the public internets, aren't they?

They'd put Widevine or PlayReady DRM on the website if they could, I'm sure.

why can't they?

because they're only for video files?

The 2. Thank you.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: