{"article":{"slug":"the-tilde-in-your-path-may-not-be-your-home","title":"The tilde in your PATH may not be your HOME","subtitle":null,"summary":"A short warning that writing export PATH=\"$PATH:~/.local/bin/\" in a shell rc file leaves a literal tilde in PATH because tilde expansion only happens in unquoted words, which can let sandboxed tools write to unexpected directories; it shows how to check for and fix it with $HOME.","content_type":"tutorial","language":"en","canonical_url":"https://disconnect3d.pl/2026/10/02/dont-put-tilde-in-your-path/","author":{"name":"disconnect3d","url":null,"person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"disconnect3d.pl","url":"https://disconnect3d.pl/","listing_slug":null,"listing":null},"topics":[{"name":"Security","slug":"security","url":"https://listedarticles.com/topics/security"},{"name":"Programming","slug":"programming","url":"https://listedarticles.com/topics/programming"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":373,"reading_minutes":2,"published_at":"2026-10-02T00:00:00.000Z","added_at":"2026-10-11T14:10:07.721Z","updated_at":"2026-10-11T14:10:07.721Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/the-tilde-in-your-path-may-not-be-your-home","markdown_url":"https://listedarticles.com/articles/the-tilde-in-your-path-may-not-be-your-home.md","example":false,"citation":"disconnect3d, disconnect3d.pl. \"The tilde in your PATH may not be your HOME.\" 2 Oct 2026. https://disconnect3d.pl/2026/10/02/dont-put-tilde-in-your-path/ (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://disconnect3d.pl/2026/10/02/dont-put-tilde-in-your-path/"},"body_markdown":"I was playing with the [nono](https://nono.sh/) agent sandboxing tool and it greeted me with a warning: `PATH entries the sandbox can write to: ~/.local/bin/` which looked suspicious.\n\n![nono warning about PATH entries the sandbox can write to](https://disconnect3d.pl/assets/posts/tilde-in-path-nono-warning.png)\n\nIn other words, doing this in your `~/.bashrc` or `~/.zshrc`:\n\n```\nexport PATH=\"$PATH:~/.local/bin/\"\n```\n\nwill not expand the `~` (tilde) into the home path (or `$HOME`) as the tilde to home expansion happens only in unquoted inputs, as also the [bash documentation says](https://www.gnu.org/software/bash/manual/html_node/Tilde-Expansion.html):\n\n> If a word begins with an unquoted tilde character (‘~’), all of the characters up to the first unquoted slash (…) are considered a tilde-prefix. (…)\n>\n> Bash checks each variable assignment for unquoted tilde-prefixes immediately following a ‘:’ or the first ‘=’, and performs tilde expansion in these cases. (…)\n\nSo instead of having `/home/<user>/.local/bin/` added to `PATH` we end up with `./~/.local/bin/` added to `PATH`.\n\nAnd to fix this, we can do this:\n\n```\nexport PATH=\"$PATH:$HOME/.local/bin/\"\n```\n\nNote that the unquoted version `export PATH=$PATH:~/.local/bin` actually works in Bash and Zsh, because tilde expansion is also performed in variable assignments after `=` and after each `:`. But relying on that is fragile as for example, a whitespace will break the variable assignment.\n\nThe problem can also be seen here:\n\n```\n$ ls -la\ntotal 0\ndrwxr-xr-x@   2 dc  staff    64 Oct  2 13:37 .\ndrwxr-x---+ 105 dc  staff  3360 Oct  2 13:37 ..\n$ mkdir -p ./~/.local/bin/\n$ printf '#include <stdio.h>\\nint main() { puts(\"hello\"); }'>a.c; gcc a.c -o ./~/.local/bin/kek\n$ PATH=\"~/.local/bin/\" kek\nhello\n$ tree -f\n.\n├── ./~\n│   └── ./~/.local\n│       └── ./~/.local/bin\n│           └── ./~/.local/bin/kek\n└── ./a.c\n\n4 directories, 2 files\n```\n\n![Demo showing that a literal tilde in PATH resolves to a ./~/ directory in the current working directory](https://disconnect3d.pl/assets/posts/tilde-in-path.png)\n\nAs we can see, the `kek` binary was found and executed from `./~/.local/bin/` — the home directory was never involved.\n\n## Check your PATH\n\nYou can quickly check whether you have this problem with:\n\n```\n$ echo \"$PATH\" | grep -- '~'\n```\n\nor, to see each entry on its own line:\n\n```\n$ echo \"$PATH\" | tr ':' '\\n' | grep '~'\n~/.local/bin/\n```\n\nIf it prints anything, go fix your `.bashrc`/`.zshrc`/`.profile` and replace the `~` with `$HOME` :).\n\nBtw, kudos to the nono tool for warning about this - even though the warning could be more verbose (PR incoming).\n","body_html":"<p>I was playing with the <a href=\"https://nono.sh/\" rel=\"nofollow ugc noopener\">nono</a> agent sandboxing tool and it greeted me with a warning: <code>PATH entries the sandbox can write to: ~/.local/bin/</code> which looked suspicious.</p>\n<figure><img src=\"https://disconnect3d.pl/assets/posts/tilde-in-path-nono-warning.png\" alt=\"nono warning about PATH entries the sandbox can write to\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></figure>\n<p>In other words, doing this in your <code>~/.bashrc</code> or <code>~/.zshrc</code>:</p>\n<pre><code>export PATH=&quot;$PATH:~/.local/bin/&quot;</code></pre>\n<p>will not expand the <code>~</code> (tilde) into the home path (or <code>$HOME</code>) as the tilde to home expansion happens only in unquoted inputs, as also the <a href=\"https://www.gnu.org/software/bash/manual/html_node/Tilde-Expansion.html\" rel=\"nofollow ugc noopener\">bash documentation says</a>:</p>\n<blockquote><p>If a word begins with an unquoted tilde character (‘~’), all of the characters up to the first unquoted slash (…) are considered a tilde-prefix. (…)</p>\n<p>Bash checks each variable assignment for unquoted tilde-prefixes immediately following a ‘:’ or the first ‘=’, and performs tilde expansion in these cases. (…)</p></blockquote>\n<p>So instead of having <code>/home/&lt;user&gt;/.local/bin/</code> added to <code>PATH</code> we end up with <code>./~/.local/bin/</code> added to <code>PATH</code>.</p>\n<p>And to fix this, we can do this:</p>\n<pre><code>export PATH=&quot;$PATH:$HOME/.local/bin/&quot;</code></pre>\n<p>Note that the unquoted version <code>export PATH=$PATH:~/.local/bin</code> actually works in Bash and Zsh, because tilde expansion is also performed in variable assignments after <code>=</code> and after each <code>:</code>. But relying on that is fragile as for example, a whitespace will break the variable assignment.</p>\n<p>The problem can also be seen here:</p>\n<pre><code>$ ls -la\ntotal 0\ndrwxr-xr-x@   2 dc  staff    64 Oct  2 13:37 .\ndrwxr-x---+ 105 dc  staff  3360 Oct  2 13:37 ..\n$ mkdir -p ./~/.local/bin/\n$ printf &#39;#include &lt;stdio.h&gt;\\nint main() { puts(&quot;hello&quot;); }&#39;&gt;a.c; gcc a.c -o ./~/.local/bin/kek\n$ PATH=&quot;~/.local/bin/&quot; kek\nhello\n$ tree -f\n.\n├── ./~\n│   └── ./~/.local\n│       └── ./~/.local/bin\n│           └── ./~/.local/bin/kek\n└── ./a.c\n\n4 directories, 2 files</code></pre>\n<figure><img src=\"https://disconnect3d.pl/assets/posts/tilde-in-path.png\" alt=\"Demo showing that a literal tilde in PATH resolves to a ./~/ directory in the current working directory\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></figure>\n<p>As we can see, the <code>kek</code> binary was found and executed from <code>./~/.local/bin/</code> — the home directory was never involved.</p>\n<h2 id=\"check-your-path\">Check your PATH</h2>\n<p>You can quickly check whether you have this problem with:</p>\n<pre><code>$ echo &quot;$PATH&quot; | grep -- &#39;~&#39;</code></pre>\n<p>or, to see each entry on its own line:</p>\n<pre><code>$ echo &quot;$PATH&quot; | tr &#39;:&#39; &#39;\\n&#39; | grep &#39;~&#39;\n~/.local/bin/</code></pre>\n<p>If it prints anything, go fix your <code>.bashrc</code>/<code>.zshrc</code>/<code>.profile</code> and replace the <code>~</code> with <code>$HOME</code> :).</p>\n<p>Btw, kudos to the nono tool for warning about this - even though the warning could be more verbose (PR incoming).</p>","headings":[{"level":2,"text":"Check your PATH","id":"check-your-path"}]}}