mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-02 08:33:36 +00:00
This fixes a critical security issue where path parameters from client requests were not validated against ALLOWED_ROOT_DIRECTORY, allowing attackers to access files and directories outside the configured root directory. Changes: - Add validatePath() checks to 29 route handlers that accept path parameters - Validate paths in agent routes (workingDirectory, imagePaths) - Validate paths in feature routes (projectPath) - Validate paths in worktree routes (projectPath, worktreePath) - Validate paths in git routes (projectPath, filePath) - Validate paths in auto-mode routes (projectPath, worktreePath) - Validate paths in settings/suggestions routes (projectPath) - Return 403 Forbidden for paths outside ALLOWED_ROOT_DIRECTORY - Maintain backward compatibility (unrestricted when env var not set) Security Impact: - Prevents directory traversal attacks - Prevents unauthorized file access - Prevents arbitrary code execution via unvalidated paths All validation follows the existing pattern in fs routes and session creation, using the validatePath() function from lib/security.ts which checks against both ALLOWED_ROOT_DIRECTORY and DATA_DIR (appData). Tests: All 653 unit tests passing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
/**
|
|
* PUT /api/settings/project - Update project-specific settings
|
|
*
|
|
* Updates settings for a specific project. Partial updates supported.
|
|
* Project settings override global settings when present.
|
|
*
|
|
* Request body: `{ projectPath: string, updates: Partial<ProjectSettings> }`
|
|
* Response: `{ "success": true, "settings": ProjectSettings }`
|
|
*/
|
|
|
|
import type { Request, Response } from "express";
|
|
import type { SettingsService } from "../../../services/settings-service.js";
|
|
import type { ProjectSettings } from "../../../types/settings.js";
|
|
import { getErrorMessage, logError } from "../common.js";
|
|
import { validatePath, PathNotAllowedError } from "../../../lib/security.js";
|
|
|
|
/**
|
|
* Create handler factory for PUT /api/settings/project
|
|
*
|
|
* @param settingsService - Instance of SettingsService for file I/O
|
|
* @returns Express request handler
|
|
*/
|
|
export function createUpdateProjectHandler(settingsService: SettingsService) {
|
|
return async (req: Request, res: Response): Promise<void> => {
|
|
try {
|
|
const { projectPath, updates } = req.body as {
|
|
projectPath?: string;
|
|
updates?: Partial<ProjectSettings>;
|
|
};
|
|
|
|
if (!projectPath || typeof projectPath !== "string") {
|
|
res.status(400).json({
|
|
success: false,
|
|
error: "projectPath is required",
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (!updates || typeof updates !== "object") {
|
|
res.status(400).json({
|
|
success: false,
|
|
error: "updates object is required",
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Validate paths are within ALLOWED_ROOT_DIRECTORY
|
|
try {
|
|
validatePath(projectPath);
|
|
} catch (error) {
|
|
if (error instanceof PathNotAllowedError) {
|
|
res.status(403).json({
|
|
success: false,
|
|
error: error.message,
|
|
});
|
|
return;
|
|
}
|
|
throw error;
|
|
}
|
|
|
|
const settings = await settingsService.updateProjectSettings(
|
|
projectPath,
|
|
updates
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
settings,
|
|
});
|
|
} catch (error) {
|
|
logError(error, "Update project settings failed");
|
|
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
|
}
|
|
};
|
|
}
|