<p dir="auto">If <code class="notranslate">test.ts</code> is:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="const { symlinkSync, readFileSync } = Deno;

try {
  const s = readFileSync(&quot;./test_private/file&quot;);
  console.log(s);
} catch(e) {
  console.log(&quot;caught&quot;, e.name);
}

symlinkSync(&quot;./test_private/file&quot;, &quot;./test_public/file&quot;);
const s = readFileSync(&quot;./test_public/file&quot;);
console.log(&quot;success!&quot;, new TextDecoder().decode(s));"><pre class="notranslate"><code class="notranslate">const { symlinkSync, readFileSync } = Deno;

try {
  const s = readFileSync("./test_private/file");
  console.log(s);
} catch(e) {
  console.log("caught", e.name);
}

symlinkSync("./test_private/file", "./test_public/file");
const s = readFileSync("./test_public/file");
console.log("success!", new TextDecoder().decode(s));
</code></pre></div>
<p dir="auto">Then:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="$ deno --version
deno 0.36.0
v8 8.1.310
typescript 3.8.3
$ mkdir test_private test_public
$ echo data &gt; test_private/file
$ deno --allow-read=./test_public --allow-write=./test_public test.ts
caught PermissionDenied
success! data"><pre class="notranslate"><code class="notranslate">$ deno --version
deno 0.36.0
v8 8.1.310
typescript 3.8.3
$ mkdir test_private test_public
$ echo data &gt; test_private/file
$ deno --allow-read=./test_public --allow-write=./test_public test.ts
caught PermissionDenied
success! data
</code></pre></div>
<p dir="auto">Hence, if I know that <code class="notranslate">./test_private/file</code> exists, and have <code class="notranslate">--allow-read --allow-write</code> access anywhere, I can create a symlink to <code class="notranslate">./test_private/file</code> and put it in the second location, giving me (at least) read access to <code class="notranslate">./test_private/file</code>. (I verified that I'll also have write access to it.)</p>
<p dir="auto">Combined with the issues in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="583933332" data-permission-text="Title is private" data-url="https://github.com/denoland/deno/issues/4423" data-hovercard-type="issue" data-hovercard-url="/denoland/deno/issues/4423/hovercard" href="https://github.com/denoland/deno/issues/4423">#4423</a>, if I have only <code class="notranslate">--allow-write</code> but not <code class="notranslate">--allow-read</code> access to <code class="notranslate">./test_private</code>, I have the means to query the existence of any paths underneath it.</p>
<p dir="auto">We could partly address this by having <code class="notranslate">op_symlink</code> require <code class="notranslate">--allow-read</code> access on its source file. I don't know if that would break the ability to create symlinks to non-existent paths. I don't think it would prevent one from gaining write access to any path they had read access to, if they had read/write access to any other path (such as <code class="notranslate">/tmp</code>).</p>
<p dir="auto">A different strategy for addressing might be to have our <code class="notranslate">state.check_read</code>/<code class="notranslate">check_write</code> machinery follow symlinks?</p>
<p dir="auto">e.g. Currently creating a symlink under write-allowed directory to other directories would allow escaping the perm rules and access any file.</p>