已开启
Fix CVE-2026-58039 #261
Fix CVE-2026-58039 #261
已开启
易大夫创建于 20 天前
共 3 个文件变更+512-0
@@ -0,0 +1,166 @@
1+From 9a6b7e343a42061c44fa567d557fef7a347a8099 Mon Sep 17 00:00:00 2001
2+From: RafaelGSS <rafael.nunu@hotmail.com>
3+Date: Fri, 26 Jun 2026 19:08:22 -0300
4+Subject: [PATCH] permission: check final report output path
5+ 
6+Refs: https://hackerone.com/reports/3815767
7+Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com>
8+PR-URL: https://github.com/nodejs-private/node-private/pull/926
9+CVE-ID: CVE-2026-58039
10+---
11+ lib/internal/process/report.js | 10 ++-
12+ src/node_report.cc | 22 ++++---
13+ .../test-permission-fs-write-report.js | 65 +++++++++++++++++++
14+ 3 files changed, 86 insertions(+), 11 deletions(-)
15+ 
16+diff --git a/lib/internal/process/report.js b/lib/internal/process/report.js
17+index 7b34af0e289f..c383dc8caeb8 100644
18+--- a/lib/internal/process/report.js
19++++ b/lib/internal/process/report.js
20+@@ -9,6 +9,7 @@ const {
21+ ERR_SYNTHETIC,
22+ } = require('internal/errors').codes;
23+ const { getValidatedPath } = require('internal/fs/utils');
24++const { sep } = require('path');
25+ const permission = require('internal/process/permission');
26+ const {
27+ validateBoolean,
28+@@ -29,7 +30,14 @@ const report = {
29+ }
30+
31+ if (permission.isEnabled()) {
32+- const resource = file ?? process.cwd();
33++ let resource = file;
34++ if (resource !== undefined) {
35++ const directory = nr.getDirectory();
36++ if (directory !== '')
37++ resource = `${directory}${sep}${resource}`;
38++ } else {
39++ resource = process.cwd();
40++ }
41+ if (!permission.has('fs.write', resource)) {
42+ throw new ERR_ACCESS_DENIED(
43+ 'Access to this API has been restricted',
44+diff --git a/src/node_report.cc b/src/node_report.cc
45+index ba2dd7e676bf..04c5d415c3c6 100644
46+--- a/src/node_report.cc
47++++ b/src/node_report.cc
48+@@ -855,13 +855,6 @@ std::string TriggerNodeReport(Isolate* isolate,
49+ filename = *DiagnosticFilename(
50+ env != nullptr ? env->thread_id() : 0, "report", "json");
51+ }
52+- if (env != nullptr) {
53+- THROW_IF_INSUFFICIENT_PERMISSIONS(
54+- env,
55+- permission::PermissionScope::kFileSystemWrite,
56+- Environment::GetCwd(env->exec_path()),
57+- filename);
58+- }
59+ }
60+
61+ // Open the report file stream for writing. Supports stdout/err,
62+@@ -879,12 +872,21 @@ std::string TriggerNodeReport(Isolate* isolate,
63+ report_directory = per_process::cli_options->report_directory;
64+ }
65+ // Regular file. Append filename to directory path if one was specified
66++ std::string pathname;
67+ if (report_directory.length() > 0) {
68+- std::string pathname = report_directory + kPathSeparator + filename;
69+- outfile.open(pathname, std::ios::out | std::ios::binary);
70++ pathname = report_directory + kPathSeparator + filename;
71+ } else {
72+- outfile.open(filename, std::ios::out | std::ios::binary);
73++ pathname = filename;
74++ }
75++
76++ // We may not always be in a great state when generating a node report.
77++ // Allow for the case where we don't have an env.
78++ if (env != nullptr) {
79++ THROW_IF_INSUFFICIENT_PERMISSIONS(
80++ env, permission::PermissionScope::kFileSystemWrite, pathname, "");
81+ }
82++
83++ outfile.open(pathname, std::ios::out | std::ios::binary);
84+ // Check for errors on the file open
85+ if (!outfile.is_open()) {
86+ std::cerr << "\nFailed to open Node.js report file: " << filename;
87+diff --git a/test/parallel/test-permission-fs-write-report.js b/test/parallel/test-permission-fs-write-report.js
88+index 595f83b26807..728bc4d34c85 100644
89+--- a/test/parallel/test-permission-fs-write-report.js
90++++ b/test/parallel/test-permission-fs-write-report.js
91+@@ -23,6 +23,7 @@ if (!process.permission) {
92+ }
93+
94+ const assert = require('assert');
95++const fs = require('fs');
96+ const path = require('path');
97+ const tmpdir = require('../common/tmpdir');
98+
99+@@ -73,3 +74,67 @@ spawnSyncAndExitWithoutError(
100+ ],
101+ { cwd: tmpdir.path }
102+ );
103++
104++{
105++ const allowedDir = path.join(tmpdir.path, 'report-allowed');
106++ const deniedDir = path.join(tmpdir.path, 'report-denied');
107++ fs.mkdirSync(allowedDir);
108++ fs.mkdirSync(deniedDir);
109++
110++ const deniedFile = path.join(deniedDir, 'report.json');
111++ fs.writeFileSync(deniedFile, 'existing content');
112++ spawnSyncAndExitWithoutError(
113++ process.execPath,
114++ [
115++ '--permission',
116++ '--allow-fs-read=*',
117++ `--allow-fs-write=${allowedDir}`,
118++ '-e',
119++ `
120++ const assert = require('assert');
121++ process.report.directory = ${JSON.stringify(deniedDir)};
122++ assert.throws(() => {
123++ process.report.writeReport('report.json');
124++ }, {
125++ code: 'ERR_ACCESS_DENIED',
126++ permission: 'FileSystemWrite',
127++ resource: ${JSON.stringify(deniedFile)},
128++ });
129++ `,
130++ ],
131++ { cwd: allowedDir },
132++ );
133++ assert.strictEqual(fs.readFileSync(deniedFile, 'utf8'), 'existing content');
134++}
135++
136++{
137++ const allowedDir = path.join(tmpdir.path, 'report-filename-allowed');
138++ const deniedDir = path.join(tmpdir.path, 'report-filename-denied');
139++ fs.mkdirSync(allowedDir);
140++ fs.mkdirSync(deniedDir);
141++
142++ const deniedFile = path.join(deniedDir, 'report.json');
143++ spawnSyncAndExitWithoutError(
144++ process.execPath,
145++ [
146++ '--permission',
147++ '--allow-fs-read=*',
148++ `--allow-fs-write=${allowedDir}`,
149++ '-e',
150++ `
151++ const assert = require('assert');
152++ process.report.directory = ${JSON.stringify(deniedDir)};
153++ process.report.filename = 'report.json';
154++ assert.throws(() => {
155++ process.report.writeReport();
156++ }, {
157++ code: 'ERR_ACCESS_DENIED',
158++ permission: 'FileSystemWrite',
159++ resource: ${JSON.stringify(deniedFile)},
160++ });
161++ `,
162++ ],
163++ { cwd: allowedDir },
164++ );
165++ assert.strictEqual(fs.existsSync(deniedFile), false);
166++}
@@ -0,0 +1,166 @@
1+From ed18b9cc073f0b63268d6f2c84730b18e90fdd20 Mon Sep 17 00:00:00 2001
2+From: RafaelGSS <rafael.nunu@hotmail.com>
3+Date: Fri, 26 Jun 2026 19:08:22 -0300
4+Subject: [PATCH] permission: check final report output path
5+ 
6+Refs: https://hackerone.com/reports/3815767
7+Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com>
8+PR-URL: https://github.com/nodejs-private/node-private/pull/926
9+CVE-ID: CVE-2026-58039
10+---
11+ lib/internal/process/report.js | 10 ++-
12+ src/node_report.cc | 22 ++++---
13+ .../test-permission-fs-write-report.js | 65 +++++++++++++++++++
14+ 3 files changed, 86 insertions(+), 11 deletions(-)
15+ 
16+diff --git a/lib/internal/process/report.js b/lib/internal/process/report.js
17+index 7b34af0e289f..c383dc8caeb8 100644
18+--- a/lib/internal/process/report.js
19++++ b/lib/internal/process/report.js
20+@@ -9,6 +9,7 @@ const {
21+ ERR_SYNTHETIC,
22+ } = require('internal/errors').codes;
23+ const { getValidatedPath } = require('internal/fs/utils');
24++const { sep } = require('path');
25+ const permission = require('internal/process/permission');
26+ const {
27+ validateBoolean,
28+@@ -29,7 +30,14 @@ const report = {
29+ }
30+
31+ if (permission.isEnabled()) {
32+- const resource = file ?? process.cwd();
33++ let resource = file;
34++ if (resource !== undefined) {
35++ const directory = nr.getDirectory();
36++ if (directory !== '')
37++ resource = `${directory}${sep}${resource}`;
38++ } else {
39++ resource = process.cwd();
40++ }
41+ if (!permission.has('fs.write', resource)) {
42+ throw new ERR_ACCESS_DENIED(
43+ 'Access to this API has been restricted',
44+diff --git a/src/node_report.cc b/src/node_report.cc
45+index e1f4e30417d1..ead720dd02dd 100644
46+--- a/src/node_report.cc
47++++ b/src/node_report.cc
48+@@ -851,13 +851,6 @@ std::string TriggerNodeReport(Isolate* isolate,
49+ filename = *DiagnosticFilename(
50+ env != nullptr ? env->thread_id() : 0, "report", "json");
51+ }
52+- if (env != nullptr) {
53+- THROW_IF_INSUFFICIENT_PERMISSIONS(
54+- env,
55+- permission::PermissionScope::kFileSystemWrite,
56+- Environment::GetCwd(env->exec_path()),
57+- filename);
58+- }
59+ }
60+
61+ // Open the report file stream for writing. Supports stdout/err,
62+@@ -875,12 +868,21 @@ std::string TriggerNodeReport(Isolate* isolate,
63+ report_directory = per_process::cli_options->report_directory;
64+ }
65+ // Regular file. Append filename to directory path if one was specified
66++ std::string pathname;
67+ if (report_directory.length() > 0) {
68+- std::string pathname = report_directory + kPathSeparator + filename;
69+- outfile.open(pathname, std::ios::out | std::ios::binary);
70++ pathname = report_directory + kPathSeparator + filename;
71+ } else {
72+- outfile.open(filename, std::ios::out | std::ios::binary);
73++ pathname = filename;
74++ }
75++
76++ // We may not always be in a great state when generating a node report.
77++ // Allow for the case where we don't have an env.
78++ if (env != nullptr) {
79++ THROW_IF_INSUFFICIENT_PERMISSIONS(
80++ env, permission::PermissionScope::kFileSystemWrite, pathname, "");
81+ }
82++
83++ outfile.open(pathname, std::ios::out | std::ios::binary);
84+ // Check for errors on the file open
85+ if (!outfile.is_open()) {
86+ std::cerr << "\nFailed to open Node.js report file: " << filename;
87+diff --git a/test/parallel/test-permission-fs-write-report.js b/test/parallel/test-permission-fs-write-report.js
88+index 595f83b26807..728bc4d34c85 100644
89+--- a/test/parallel/test-permission-fs-write-report.js
90++++ b/test/parallel/test-permission-fs-write-report.js
91+@@ -23,6 +23,7 @@ if (!process.permission) {
92+ }
93+
94+ const assert = require('assert');
95++const fs = require('fs');
96+ const path = require('path');
97+ const tmpdir = require('../common/tmpdir');
98+
99+@@ -73,3 +74,67 @@ spawnSyncAndExitWithoutError(
100+ ],
101+ { cwd: tmpdir.path }
102+ );
103++
104++{
105++ const allowedDir = path.join(tmpdir.path, 'report-allowed');
106++ const deniedDir = path.join(tmpdir.path, 'report-denied');
107++ fs.mkdirSync(allowedDir);
108++ fs.mkdirSync(deniedDir);
109++
110++ const deniedFile = path.join(deniedDir, 'report.json');
111++ fs.writeFileSync(deniedFile, 'existing content');
112++ spawnSyncAndExitWithoutError(
113++ process.execPath,
114++ [
115++ '--permission',
116++ '--allow-fs-read=*',
117++ `--allow-fs-write=${allowedDir}`,
118++ '-e',
119++ `
120++ const assert = require('assert');
121++ process.report.directory = ${JSON.stringify(deniedDir)};
122++ assert.throws(() => {
123++ process.report.writeReport('report.json');
124++ }, {
125++ code: 'ERR_ACCESS_DENIED',
126++ permission: 'FileSystemWrite',
127++ resource: ${JSON.stringify(deniedFile)},
128++ });
129++ `,
130++ ],
131++ { cwd: allowedDir },
132++ );
133++ assert.strictEqual(fs.readFileSync(deniedFile, 'utf8'), 'existing content');
134++}
135++
136++{
137++ const allowedDir = path.join(tmpdir.path, 'report-filename-allowed');
138++ const deniedDir = path.join(tmpdir.path, 'report-filename-denied');
139++ fs.mkdirSync(allowedDir);
140++ fs.mkdirSync(deniedDir);
141++
142++ const deniedFile = path.join(deniedDir, 'report.json');
143++ spawnSyncAndExitWithoutError(
144++ process.execPath,
145++ [
146++ '--permission',
147++ '--allow-fs-read=*',
148++ `--allow-fs-write=${allowedDir}`,
149++ '-e',
150++ `
151++ const assert = require('assert');
152++ process.report.directory = ${JSON.stringify(deniedDir)};
153++ process.report.filename = 'report.json';
154++ assert.throws(() => {
155++ process.report.writeReport();
156++ }, {
157++ code: 'ERR_ACCESS_DENIED',
158++ permission: 'FileSystemWrite',
159++ resource: ${JSON.stringify(deniedFile)},
160++ });
161++ `,
162++ ],
163++ { cwd: allowedDir },
164++ );
165++ assert.strictEqual(fs.existsSync(deniedFile), false);
166++}
@@ -0,0 +1,180 @@
1+From 61222008b756c6da5e5ccad39e49bb5764379d21 Mon Sep 17 00:00:00 2001
2+From: RafaelGSS <rafael.nunu@hotmail.com>
3+Date: Fri, 26 Jun 2026 19:08:22 -0300
4+Subject: [PATCH] permission: check final report output path
5+ 
6+Refs: https://hackerone.com/reports/3815767
7+Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com>
8+PR-URL: https://github.com/nodejs-private/node-private/pull/908
9+CVE-ID: CVE-2026-58039
10+---
11+ lib/internal/process/report.js | 10 ++-
12+ src/node_report.cc | 29 ++++-----
13+ .../test-permission-fs-write-report.js | 65 +++++++++++++++++++
14+ 3 files changed, 86 insertions(+), 18 deletions(-)
15+ 
16+diff --git a/lib/internal/process/report.js b/lib/internal/process/report.js
17+index 7b34af0e289f..c383dc8caeb8 100644
18+--- a/lib/internal/process/report.js
19++++ b/lib/internal/process/report.js
20+@@ -9,6 +9,7 @@ const {
21+ ERR_SYNTHETIC,
22+ } = require('internal/errors').codes;
23+ const { getValidatedPath } = require('internal/fs/utils');
24++const { sep } = require('path');
25+ const permission = require('internal/process/permission');
26+ const {
27+ validateBoolean,
28+@@ -29,7 +30,14 @@ const report = {
29+ }
30+
31+ if (permission.isEnabled()) {
32+- const resource = file ?? process.cwd();
33++ let resource = file;
34++ if (resource !== undefined) {
35++ const directory = nr.getDirectory();
36++ if (directory !== '')
37++ resource = `${directory}${sep}${resource}`;
38++ } else {
39++ resource = process.cwd();
40++ }
41+ if (!permission.has('fs.write', resource)) {
42+ throw new ERR_ACCESS_DENIED(
43+ 'Access to this API has been restricted',
44+diff --git a/src/node_report.cc b/src/node_report.cc
45+index 5400ef9f4dbf..a1c954c91e64 100644
46+--- a/src/node_report.cc
47++++ b/src/node_report.cc
48+@@ -835,13 +835,6 @@ std::string TriggerNodeReport(Isolate* isolate,
49+ // 1) supplied on API 2) configured on startup 3) default generated
50+ if (!name.empty()) {
51+ filename = name;
52+- // we may not always be in a great state when generating a node report
53+- // allow for the case where we don't have an env
54+- if (env != nullptr) {
55+- THROW_IF_INSUFFICIENT_PERMISSIONS(
56+- env, permission::PermissionScope::kFileSystemWrite, name, filename);
57+- // Filename was specified as API parameter.
58+- }
59+ } else {
60+ std::string report_filename;
61+ {
62+@@ -855,13 +848,6 @@ std::string TriggerNodeReport(Isolate* isolate,
63+ filename = *DiagnosticFilename(
64+ env != nullptr ? env->thread_id() : 0, "report", "json");
65+ }
66+- if (env != nullptr) {
67+- THROW_IF_INSUFFICIENT_PERMISSIONS(
68+- env,
69+- permission::PermissionScope::kFileSystemWrite,
70+- Environment::GetCwd(env->exec_path()),
71+- filename);
72+- }
73+ }
74+
75+ // Open the report file stream for writing. Supports stdout/err,
76+@@ -879,12 +865,21 @@ std::string TriggerNodeReport(Isolate* isolate,
77+ report_directory = per_process::cli_options->report_directory;
78+ }
79+ // Regular file. Append filename to directory path if one was specified
80++ std::string pathname;
81+ if (report_directory.length() > 0) {
82+- std::string pathname = report_directory + kPathSeparator + filename;
83+- outfile.open(pathname, std::ios::out | std::ios::binary);
84++ pathname = report_directory + kPathSeparator + filename;
85+ } else {
86+- outfile.open(filename, std::ios::out | std::ios::binary);
87++ pathname = filename;
88+ }
89++
90++ // We may not always be in a great state when generating a node report.
91++ // Allow for the case where we don't have an env.
92++ if (env != nullptr) {
93++ THROW_IF_INSUFFICIENT_PERMISSIONS(
94++ env, permission::PermissionScope::kFileSystemWrite, pathname, "");
95++ }
96++
97++ outfile.open(pathname, std::ios::out | std::ios::binary);
98+ // Check for errors on the file open
99+ if (!outfile.is_open()) {
100+ std::cerr << "\nFailed to open Node.js report file: " << filename;
101+diff --git a/test/parallel/test-permission-fs-write-report.js b/test/parallel/test-permission-fs-write-report.js
102+index 595f83b26807..728bc4d34c85 100644
103+--- a/test/parallel/test-permission-fs-write-report.js
104++++ b/test/parallel/test-permission-fs-write-report.js
105+@@ -23,6 +23,7 @@ if (!process.permission) {
106+ }
107+
108+ const assert = require('assert');
109++const fs = require('fs');
110+ const path = require('path');
111+ const tmpdir = require('../common/tmpdir');
112+
113+@@ -73,3 +74,67 @@ spawnSyncAndExitWithoutError(
114+ ],
115+ { cwd: tmpdir.path }
116+ );
117++
118++{
119++ const allowedDir = path.join(tmpdir.path, 'report-allowed');
120++ const deniedDir = path.join(tmpdir.path, 'report-denied');
121++ fs.mkdirSync(allowedDir);
122++ fs.mkdirSync(deniedDir);
123++
124++ const deniedFile = path.join(deniedDir, 'report.json');
125++ fs.writeFileSync(deniedFile, 'existing content');
126++ spawnSyncAndExitWithoutError(
127++ process.execPath,
128++ [
129++ '--permission',
130++ '--allow-fs-read=*',
131++ `--allow-fs-write=${allowedDir}`,
132++ '-e',
133++ `
134++ const assert = require('assert');
135++ process.report.directory = ${JSON.stringify(deniedDir)};
136++ assert.throws(() => {
137++ process.report.writeReport('report.json');
138++ }, {
139++ code: 'ERR_ACCESS_DENIED',
140++ permission: 'FileSystemWrite',
141++ resource: ${JSON.stringify(deniedFile)},
142++ });
143++ `,
144++ ],
145++ { cwd: allowedDir },
146++ );
147++ assert.strictEqual(fs.readFileSync(deniedFile, 'utf8'), 'existing content');
148++}
149++
150++{
151++ const allowedDir = path.join(tmpdir.path, 'report-filename-allowed');
152++ const deniedDir = path.join(tmpdir.path, 'report-filename-denied');
153++ fs.mkdirSync(allowedDir);
154++ fs.mkdirSync(deniedDir);
155++
156++ const deniedFile = path.join(deniedDir, 'report.json');
157++ spawnSyncAndExitWithoutError(
158++ process.execPath,
159++ [
160++ '--permission',
161++ '--allow-fs-read=*',
162++ `--allow-fs-write=${allowedDir}`,
163++ '-e',
164++ `
165++ const assert = require('assert');
166++ process.report.directory = ${JSON.stringify(deniedDir)};
167++ process.report.filename = 'report.json';
168++ assert.throws(() => {
169++ process.report.writeReport();
170++ }, {
171++ code: 'ERR_ACCESS_DENIED',
172++ permission: 'FileSystemWrite',
173++ resource: ${JSON.stringify(deniedFile)},
174++ });
175++ `,
176++ ],
177++ { cwd: allowedDir },
178++ );
179++ assert.strictEqual(fs.existsSync(deniedFile), false);
180++}