fix: block group folder path escapes
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
import { ChildProcess, exec, spawn } from 'child_process';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
import {
|
||||
@@ -16,6 +15,7 @@ import {
|
||||
IDLE_TIMEOUT,
|
||||
} from './config.js';
|
||||
import { readEnvFile } from './env.js';
|
||||
import { resolveGroupFolderPath, resolveGroupIpcPath } from './group-folder.js';
|
||||
import { logger } from './logger.js';
|
||||
import { CONTAINER_RUNTIME_BIN, readonlyMountArgs, stopContainer } from './container-runtime.js';
|
||||
import { validateAdditionalMounts } from './mount-security.js';
|
||||
@@ -25,16 +25,6 @@ import { RegisteredGroup } from './types.js';
|
||||
const OUTPUT_START_MARKER = '---NANOCLAW_OUTPUT_START---';
|
||||
const OUTPUT_END_MARKER = '---NANOCLAW_OUTPUT_END---';
|
||||
|
||||
function getHomeDir(): string {
|
||||
const home = process.env.HOME || os.homedir();
|
||||
if (!home) {
|
||||
throw new Error(
|
||||
'Unable to determine home directory: HOME environment variable is not set and os.homedir() returned empty',
|
||||
);
|
||||
}
|
||||
return home;
|
||||
}
|
||||
|
||||
export interface ContainerInput {
|
||||
prompt: string;
|
||||
sessionId?: string;
|
||||
@@ -63,8 +53,8 @@ function buildVolumeMounts(
|
||||
isMain: boolean,
|
||||
): VolumeMount[] {
|
||||
const mounts: VolumeMount[] = [];
|
||||
const homeDir = getHomeDir();
|
||||
const projectRoot = process.cwd();
|
||||
const groupDir = resolveGroupFolderPath(group.folder);
|
||||
|
||||
if (isMain) {
|
||||
// Main gets the project root read-only. Writable paths the agent needs
|
||||
@@ -80,14 +70,14 @@ function buildVolumeMounts(
|
||||
|
||||
// Main also gets its group folder as the working directory
|
||||
mounts.push({
|
||||
hostPath: path.join(GROUPS_DIR, group.folder),
|
||||
hostPath: groupDir,
|
||||
containerPath: '/workspace/group',
|
||||
readonly: false,
|
||||
});
|
||||
} else {
|
||||
// Other groups only get their own folder
|
||||
mounts.push({
|
||||
hostPath: path.join(GROUPS_DIR, group.folder),
|
||||
hostPath: groupDir,
|
||||
containerPath: '/workspace/group',
|
||||
readonly: false,
|
||||
});
|
||||
@@ -149,7 +139,7 @@ function buildVolumeMounts(
|
||||
|
||||
// Per-group IPC namespace: each group gets its own IPC directory
|
||||
// This prevents cross-group privilege escalation via IPC
|
||||
const groupIpcDir = path.join(DATA_DIR, 'ipc', group.folder);
|
||||
const groupIpcDir = resolveGroupIpcPath(group.folder);
|
||||
fs.mkdirSync(path.join(groupIpcDir, 'messages'), { recursive: true });
|
||||
fs.mkdirSync(path.join(groupIpcDir, 'tasks'), { recursive: true });
|
||||
fs.mkdirSync(path.join(groupIpcDir, 'input'), { recursive: true });
|
||||
@@ -228,7 +218,7 @@ export async function runContainerAgent(
|
||||
): Promise<ContainerOutput> {
|
||||
const startTime = Date.now();
|
||||
|
||||
const groupDir = path.join(GROUPS_DIR, group.folder);
|
||||
const groupDir = resolveGroupFolderPath(group.folder);
|
||||
fs.mkdirSync(groupDir, { recursive: true });
|
||||
|
||||
const mounts = buildVolumeMounts(group, input.isMain);
|
||||
@@ -259,7 +249,7 @@ export async function runContainerAgent(
|
||||
'Spawning container agent',
|
||||
);
|
||||
|
||||
const logsDir = path.join(GROUPS_DIR, group.folder, 'logs');
|
||||
const logsDir = path.join(groupDir, 'logs');
|
||||
fs.mkdirSync(logsDir, { recursive: true });
|
||||
|
||||
return new Promise((resolve) => {
|
||||
@@ -603,7 +593,7 @@ export function writeTasksSnapshot(
|
||||
}>,
|
||||
): void {
|
||||
// Write filtered tasks to the group's IPC directory
|
||||
const groupIpcDir = path.join(DATA_DIR, 'ipc', groupFolder);
|
||||
const groupIpcDir = resolveGroupIpcPath(groupFolder);
|
||||
fs.mkdirSync(groupIpcDir, { recursive: true });
|
||||
|
||||
// Main sees all tasks, others only see their own
|
||||
@@ -633,7 +623,7 @@ export function writeGroupsSnapshot(
|
||||
groups: AvailableGroup[],
|
||||
registeredJids: Set<string>,
|
||||
): void {
|
||||
const groupIpcDir = path.join(DATA_DIR, 'ipc', groupFolder);
|
||||
const groupIpcDir = resolveGroupIpcPath(groupFolder);
|
||||
fs.mkdirSync(groupIpcDir, { recursive: true });
|
||||
|
||||
// Main sees all groups; others see nothing (they can't activate groups)
|
||||
|
||||
Reference in New Issue
Block a user