fix(security): shell escape paths in HostDiskUsageService; null-prototype objects in batch parser (#2659)

* fix(core): escape path in HostDiskUsageService

* fix: always use null prototypes on operation specs

* fix: update test.yml so that tests work again
This commit is contained in:
Eric Dubé
2026-03-13 14:17:36 -07:00
committed by GitHub
parent 9169114e60
commit 9506c537ab
4 changed files with 25 additions and 10 deletions
+3 -1
View File
@@ -30,7 +30,9 @@ jobs:
env:
NODE_OPTIONS: --max-old-space-size=4096
run: |
npm ci
rm package-lock.json
          npm install -g npm@latest
          npm install
npm run build
npm run test:backend -- --coverage --coverage.reporter=json --coverage.reporter=json-summary --coverage.reporter=lcov
+1
View File
@@ -78,6 +78,7 @@
"sharp": "^0.34.3",
"sharp-bmp": "^0.1.5",
"sharp-ico": "^0.1.5",
"shescape": "^2.1.10",
"socket.io": "^4.6.2",
"socket.io-client": "^4.6.2",
"ssh2": "^1.13.0",
+8 -3
View File
@@ -118,7 +118,7 @@ _handle_multipart = async (req) => {
const Busboy = require('busboy');
const { PassThrough } = require('stream');
const params = {};
const params = Object.create(null);
const files = [];
let file_index = 0;
@@ -140,7 +140,7 @@ _handle_multipart = async (req) => {
let dst = params;
for ( let i = 0; i < key_parts.length; i++ ) {
if ( ! Object.prototype.hasOwnProperty.call(dst, key_parts[i]) ) {
dst[key_parts[i]] = {};
dst[key_parts[i]] = Object.create(null);
}
if ( !dst[key_parts[i]] || typeof dst[key_parts[i]] !== 'object' || Array.isArray(dst[key_parts[i]]) ) {
throw new Error(`Tried to set member of non-object: ${key_parts[i]} in ${fieldname}`);
@@ -173,7 +173,12 @@ _handle_multipart = async (req) => {
};
bb.on('field', (fieldname, value, _details) => {
const o = JSON.parse(value);
const o = JSON.parse(value, (key, val) => {
if ( val !== null && typeof val === 'object' && !Array.isArray(val) ) {
return Object.assign(Object.create(null), val);
}
return val;
});
for ( const k in o ) {
on_field(k, o[k]);
}
@@ -18,6 +18,7 @@
*/
const BaseService = require('./BaseService');
const { execSync } = require('child_process');
const { Shescape } = require('shescape');
const config = require('../config');
/**
@@ -112,12 +113,14 @@ class HostDiskUsageService extends BaseService {
// Get the mountpoint/drive of the current working directory in mac os
get_darwin_mountpoint (directory) {
return execSync(`df -P "${directory}" | awk 'NR==2 {print $6}'`, { encoding: 'utf-8' }).trim();
const shescape = new Shescape({ shell: 'bash', quote: true });
return execSync(`df -P ${shescape.escape(directory)} | awk 'NR==2 {print $6}'`, { encoding: 'utf-8' }).trim();
}
// Get the mountpoint/drive of the current working directory in linux
get_linux_mountpint (directory) {
return execSync(`df -P "${directory}" | awk 'NR==2 {print $6}'`, { encoding: 'utf-8' }).trim();
const shescape = new Shescape({ shell: 'bash', quote: true });
return execSync(`df -P ${shescape.escape(directory)} | awk 'NR==2 {print $6}'`, { encoding: 'utf-8' }).trim();
// TODO: Implement for linux systems
}
@@ -128,13 +131,15 @@ class HostDiskUsageService extends BaseService {
// Get the total drive capacity on the mountpoint/drive in mac os
get_disk_capacity_darwin (mountpoint) {
const disk_info = execSync(`df -P "${mountpoint}" | awk 'NR==2 {print $2}'`, { encoding: 'utf-8' }).trim().split(' ');
const shescape = new Shescape({ shell: 'bash', quote: true });
const disk_info = execSync(`df -P ${shescape.escape(mountpoint)} | awk 'NR==2 {print $2}'`, { encoding: 'utf-8' }).trim().split(' ');
return parseInt(disk_info) * 512;
}
// Get the total drive capacity on the mountpoint/drive in linux
get_disk_capacity_linux (mountpoint) {
const disk_info = execSync(`df -P "${mountpoint}" | awk 'NR==2 {print $2}'`, { encoding: 'utf-8' }).trim().split(' ');
const shescape = new Shescape({ shell: 'bash', quote: true });
const disk_info = execSync(`df -P ${shescape.escape(mountpoint)} | awk 'NR==2 {print $2}'`, { encoding: 'utf-8' }).trim().split(' ');
return parseInt(disk_info) * 1024;
}
@@ -145,13 +150,15 @@ class HostDiskUsageService extends BaseService {
// Get the free space on the mountpoint/drive in mac os
get_disk_use_darwin (mountpoint) {
const disk_info = execSync(`df -P "${mountpoint}" | awk 'NR==2 {print $4}'`, { encoding: 'utf-8' }).trim().split(' ');
const shescape = new Shescape({ shell: 'bash', quote: true });
const disk_info = execSync(`df -P ${shescape.escape(mountpoint)} | awk 'NR==2 {print $4}'`, { encoding: 'utf-8' }).trim().split(' ');
return parseInt(disk_info) * 512;
}
// Get the free space on the mountpoint/drive in linux
get_disk_use_linux (mountpoint) {
const disk_info = execSync(`df -P "${mountpoint}" | awk 'NR==2 {print $4}'`, { encoding: 'utf-8' }).trim().split(' ');
const shescape = new Shescape({ shell: 'bash', quote: true });
const disk_info = execSync(`df -P ${shescape.escape(mountpoint)} | awk 'NR==2 {print $4}'`, { encoding: 'utf-8' }).trim().split(' ');
return parseInt(disk_info) * 1024;
}