Skip to content

permission: check symlink target in cpSync (incomplete CVE-2025-55130)#63208

Open
fg0x0 wants to merge 1 commit intonodejs:mainfrom
fg0x0:fix/cpsync-symlink-permission-check
Open

permission: check symlink target in cpSync (incomplete CVE-2025-55130)#63208
fg0x0 wants to merge 1 commit intonodejs:mainfrom
fg0x0:fix/cpsync-symlink-permission-check

Conversation

@fg0x0
Copy link
Copy Markdown

@fg0x0 fg0x0 commented May 9, 2026

What

Add permission checks for symlink target paths in CpSyncCopyDir (src/node_file.cc).

Why

fs.cpSync with recursive: true copies symlinks via std::filesystem::create_symlink() and copy_symlink() without validating the symlink target against the permission model. This allows reading and writing files outside permitted paths through copied symlinks.

fs.symlinkSync was fixed for this in the CVE-2025-55130 patch (lines 1353-1357) but the same check was not added to cpSync.

Reproduction

mkdir -p /tmp/allowed/src /tmp/allowed/dest /tmp/denied
echo SECRET > /tmp/denied/secret.txt
ln -sf /tmp/denied/secret.txt /tmp/allowed/src/link

node --permission \
  --allow-fs-read=/tmp/allowed --allow-fs-write=/tmp/allowed \
  --allow-fs-read=/usr --allow-fs-read=/lib -e '
const fs = require("node:fs");
try { fs.readFileSync("/tmp/denied/secret.txt"); } catch(e) { console.log("blocked:", e.code); }
try { fs.symlinkSync("/tmp/denied/secret.txt", "/tmp/allowed/dest/link"); } catch(e) { console.log("blocked:", e.code); }
fs.cpSync("/tmp/allowed/src/", "/tmp/allowed/dest/", { recursive: true });
console.log("read:", fs.readFileSync("/tmp/allowed/dest/link", "utf8").trim());
'

Output (before fix):

blocked: ERR_ACCESS_DENIED
blocked: ERR_ACCESS_DENIED
read: SECRET

How

Added permission checks using env->permission()->is_granted() for both kFileSystemRead and kFileSystemWrite on the resolved symlink target before:

  • create_symlink() call (line ~3819)
  • create_directory_symlink() call (line ~3822)
  • copy_symlink() call in the verbatimSymlinks path (line ~3754)

Test

Added test/parallel/test-fs-cp-permission-symlink.js which verifies that fs.cpSync throws ERR_ACCESS_DENIED when copying a directory containing a symlink pointing outside the allowed permission paths.

Fixes: #63179
Refs: CVE-2025-55130

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. fs Issues and PRs related to the fs subsystem / file system. needs-ci PRs that need a full CI run. labels May 9, 2026
@fg0x0 fg0x0 force-pushed the fix/cpsync-symlink-permission-check branch from b7a57bf to 76d3603 Compare May 9, 2026 06:15
fs.cpSync with recursive:true calls create_symlink() and
copy_symlink() without checking if the symlink target is within
the allowed permission paths.

fs.symlinkSync already validates symlink targets against the
permission model (added as the fix for CVE-2025-55130 at
src/node_file.cc:1353-1357). The same check was missing in
CpSyncCopyDir for both the standard symlink copy path and the
verbatimSymlinks code path.

Add permission checks for both kFileSystemRead and
kFileSystemWrite on the resolved symlink target before
create_symlink, create_directory_symlink, and copy_symlink
calls in CpSyncCopyDir.

Fixes: nodejs#63179
Refs: CVE-2025-55130
Signed-off-by: fg0x0 <fg0x0@local>
@fg0x0 fg0x0 force-pushed the fix/cpsync-symlink-permission-check branch from 76d3603 to 7a2f106 Compare May 9, 2026 06:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. fs Issues and PRs related to the fs subsystem / file system. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fs.cpSync copies symlinks without permission check on target path

2 participants