@@ -2,6 +2,7 @@ package cmd
22
33import (
44 "fmt"
5+ "regexp"
56 "time"
67)
78
@@ -36,13 +37,53 @@ type S3Config struct {
3637 Region string
3738}
3839
40+ // validPostgreSQLIdentifier checks if a string is a valid PostgreSQL identifier
41+ // to prevent SQL injection attacks
42+ var validPostgreSQLIdentifier = regexp .MustCompile (`^[a-zA-Z_][a-zA-Z0-9_]*$` )
43+
44+ // isValidTableName validates that a table name is safe to use in SQL queries
45+ func isValidTableName (name string ) bool {
46+ // Check for empty or excessively long names
47+ if name == "" || len (name ) > 63 {
48+ return false
49+ }
50+
51+ // Must match PostgreSQL identifier rules
52+ return validPostgreSQLIdentifier .MatchString (name )
53+ }
54+
55+ // isValidRegion validates that an S3 region is reasonable
56+ func isValidRegion (region string ) bool {
57+ // Empty region is not valid (except for "auto" which is handled separately)
58+ if region == "" {
59+ return false
60+ }
61+
62+ // Region should be reasonable length
63+ if len (region ) > 50 {
64+ return false
65+ }
66+
67+ // Region should only contain alphanumeric, dash, and underscore
68+ matched , _ := regexp .MatchString (`^[a-zA-Z0-9_-]+$` , region )
69+ return matched
70+ }
71+
3972func (c * Config ) Validate () error {
73+ // Validate database configuration
4074 if c .Database .User == "" {
4175 return fmt .Errorf ("database user is required" )
4276 }
4377 if c .Database .Name == "" {
4478 return fmt .Errorf ("database name is required" )
4579 }
80+
81+ // Validate database port
82+ if c .Database .Port < 1 || c .Database .Port > 65535 {
83+ return fmt .Errorf ("database port must be between 1 and 65535, got %d" , c .Database .Port )
84+ }
85+
86+ // Validate S3 configuration
4687 if c .S3 .Endpoint == "" {
4788 return fmt .Errorf ("S3 endpoint is required" )
4889 }
@@ -55,10 +96,23 @@ func (c *Config) Validate() error {
5596 if c .S3 .SecretKey == "" {
5697 return fmt .Errorf ("S3 secret key is required" )
5798 }
99+
100+ // Validate S3 region
101+ if c .S3 .Region != "" && c .S3 .Region != "auto" {
102+ if ! isValidRegion (c .S3 .Region ) {
103+ return fmt .Errorf ("S3 region contains invalid characters or is too long: %s" , c .S3 .Region )
104+ }
105+ }
106+
107+ // Validate and sanitize table name to prevent SQL injection
58108 if c .Table == "" {
59109 return fmt .Errorf ("table name is required" )
60110 }
111+ if ! isValidTableName (c .Table ) {
112+ return fmt .Errorf ("table name '%s' is invalid: must be 1-63 characters, start with a letter or underscore, and contain only letters, numbers, and underscores" , c .Table )
113+ }
61114
115+ // Validate date formats
62116 if c .StartDate != "" {
63117 if _ , err := time .Parse ("2006-01-02" , c .StartDate ); err != nil {
64118 return fmt .Errorf ("invalid start date format: %v" , err )
@@ -70,9 +124,15 @@ func (c *Config) Validate() error {
70124 }
71125 }
72126
127+ // Validate workers count
73128 if c .Workers < 1 {
74129 return fmt .Errorf ("workers must be at least 1" )
75130 }
131+ // Prevent integer overflow and excessive resource usage
132+ // More than 1000 workers is unreasonable and could cause issues
133+ if c .Workers > 1000 {
134+ return fmt .Errorf ("workers must not exceed 1000, got %d" , c .Workers )
135+ }
76136
77137 return nil
78138}
0 commit comments