From 8dcf042ba9e9e6d4f5e81299073589df83ac530b Mon Sep 17 00:00:00 2001 From: sysy <2772196789@qq.com> Date: Sat, 18 Jul 2026 23:04:55 -0400 Subject: [PATCH] Fix path traversal in profile operations Reject profile names containing path separators or traversal sequences to prevent arbitrary filesystem delete/create/symlink. Fixes #54 --- server/profile-manager.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/server/profile-manager.js b/server/profile-manager.js index e13e5a9..722b13b 100644 --- a/server/profile-manager.js +++ b/server/profile-manager.js @@ -6,6 +6,13 @@ const HOME_DIR = os.homedir(); const OPENCODE_DIR = path.join(HOME_DIR, '.config', 'opencode'); const PROFILES_DIR = path.join(HOME_DIR, '.config', 'opencode-profiles'); +function safeName(name) { + if (!name || name.includes('/') || name.includes('\\') || name.includes('..')) { + throw new Error('Invalid profile name'); + } + return name; +} + if (!fs.existsSync(PROFILES_DIR)) { fs.mkdirSync(PROFILES_DIR, { recursive: true }); } @@ -51,6 +58,7 @@ function listProfiles() { } function createProfile(name) { + safeName(name); const dir = path.join(PROFILES_DIR, name); if (fs.existsSync(dir)) throw new Error('Profile already exists'); fs.mkdirSync(dir, { recursive: true }); @@ -58,6 +66,7 @@ function createProfile(name) { } function deleteProfile(name) { + safeName(name); const { active } = listProfiles(); if (name === active) throw new Error('Cannot delete active profile'); if (name === 'default') throw new Error('Cannot delete default profile'); @@ -70,6 +79,7 @@ function deleteProfile(name) { } function activateProfile(name) { + safeName(name); const target = path.join(PROFILES_DIR, name); if (!fs.existsSync(target)) throw new Error('Profile not found');