Skip to content

Commit 48e84c4

Browse files
Copilotkevinelliott
andcommitted
Add comprehensive input validation to prevent security vulnerabilities
- Add database port validation (1-65535) - Add S3 region validation (alphanumeric, dash, underscore only, max 50 chars) - Add table name sanitization to prevent SQL injection (PostgreSQL identifier rules) - Add workers count upper limit (max 1000) to prevent integer overflow - Add comprehensive test coverage for all validation rules Co-authored-by: kevinelliott <123112+kevinelliott@users.noreply.github.com>
1 parent 7453b28 commit 48e84c4

2 files changed

Lines changed: 407 additions & 0 deletions

File tree

cmd/config.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cmd
22

33
import (
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+
3972
func (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

Comments
 (0)