fix(#274): Add input validation to prevent command injection in git operations
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Implemented strict whitelist-based validation for git branch names and repository URLs to prevent command injection vulnerabilities in worktree operations. Security fixes: - Created git-validation.util.ts with whitelist validation functions - Added custom DTO validators for branch names and repository URLs - Applied defense-in-depth validation in WorktreeManagerService - Comprehensive test coverage (31 tests) for all validation scenarios Validation rules: - Branch names: alphanumeric + hyphens + underscores + slashes + dots only - Repository URLs: https://, http://, ssh://, git:// protocols only - Blocks: option injection (--), command substitution ($(), ``), shell operators - Prevents: SSRF attacks (localhost, internal networks), credential injection Defense layers: 1. DTO validation (first line of defense at API boundary) 2. Service-level validation (defense-in-depth before git operations) Fixes #274 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,10 +7,65 @@ import {
|
||||
IsOptional,
|
||||
ArrayNotEmpty,
|
||||
IsIn,
|
||||
Validate,
|
||||
ValidatorConstraint,
|
||||
ValidatorConstraintInterface,
|
||||
ValidationArguments,
|
||||
} from "class-validator";
|
||||
import { Type } from "class-transformer";
|
||||
import { AgentType } from "../../../spawner/types/agent-spawner.types";
|
||||
import { GateProfileType } from "../../../coordinator/types/gate-config.types";
|
||||
import { validateBranchName, validateRepositoryUrl } from "../../../git/git-validation.util";
|
||||
|
||||
/**
|
||||
* Custom validator for git branch names
|
||||
* Uses whitelist-based validation to prevent command injection
|
||||
*/
|
||||
@ValidatorConstraint({ name: "isValidBranchName", async: false })
|
||||
export class IsValidBranchName implements ValidatorConstraintInterface {
|
||||
validate(branchName: string, _args: ValidationArguments): boolean {
|
||||
try {
|
||||
validateBranchName(branchName);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
defaultMessage(args: ValidationArguments): string {
|
||||
try {
|
||||
validateBranchName(args.value as string);
|
||||
return "Branch name is invalid";
|
||||
} catch (error) {
|
||||
return error instanceof Error ? error.message : "Branch name is invalid";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom validator for git repository URLs
|
||||
* Prevents SSRF and command injection via dangerous protocols
|
||||
*/
|
||||
@ValidatorConstraint({ name: "isValidRepositoryUrl", async: false })
|
||||
export class IsValidRepositoryUrl implements ValidatorConstraintInterface {
|
||||
validate(repositoryUrl: string, _args: ValidationArguments): boolean {
|
||||
try {
|
||||
validateRepositoryUrl(repositoryUrl);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
defaultMessage(args: ValidationArguments): string {
|
||||
try {
|
||||
validateRepositoryUrl(args.value as string);
|
||||
return "Repository URL is invalid";
|
||||
} catch (error) {
|
||||
return error instanceof Error ? error.message : "Repository URL is invalid";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Context DTO for agent spawn request
|
||||
@@ -18,10 +73,12 @@ import { GateProfileType } from "../../../coordinator/types/gate-config.types";
|
||||
export class AgentContextDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Validate(IsValidRepositoryUrl)
|
||||
repository!: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Validate(IsValidBranchName)
|
||||
branch!: string;
|
||||
|
||||
@IsArray()
|
||||
|
||||
Reference in New Issue
Block a user