caddyfile: reject negative import argument indices (#8316)

{args[-1]} and {args.-1} parsed as -1 and indexed the args slice
directly, panicking with index out of range. Treat negative indices as
out of bounds, like indices past the end.
pull/7949/head^2
D'Ali Ben Macha 2026-11-03 09:15:36 +01:00 committed by GitHub
parent 43653cfb65
commit 482f867395
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 42 additions and 2 deletions

View File

@ -112,7 +112,7 @@ func makeArgsReplacer(args []string) *caddy.Replacer {
"Placeholder {args." + matches[1] + "} has an invalid index")
return nil, false
}
if value >= len(args) {
if value < 0 || value >= len(args) {
caddy.Log().Named("caddyfile").Warn(
"Placeholder {args." + matches[1] + "} index is out of bounds, only " + strconv.Itoa(len(args)) + " argument(s) exist")
return nil, false
@ -140,7 +140,7 @@ func makeArgsReplacer(args []string) *caddy.Replacer {
"Placeholder {args[" + matches[1] + "]} has an invalid index")
return nil, false
}
if value >= len(args) {
if value < 0 || value >= len(args) {
caddy.Log().Named("caddyfile").Warn(
"Placeholder {args[" + matches[1] + "]} index is out of bounds, only " + strconv.Itoa(len(args)) + " argument(s) exist")
return nil, false

View File

@ -809,6 +809,46 @@ func TestImportReplacementInJSONWithBrace(t *testing.T) {
}
}
func TestArgsReplacerOutOfBoundsIndex(t *testing.T) {
for i, test := range []struct {
args []string
input string
expect string
}{
{
args: []string{"a", "b"},
input: "{args[1]}",
expect: "b",
},
{
args: []string{"a", "b"},
input: "{args[2]}",
expect: "{args[2]}",
},
{
args: []string{"a", "b"},
input: "{args[-1]}",
expect: "{args[-1]}",
},
{
args: []string{"a", "b"},
input: "{args.-1}",
expect: "{args.-1}",
},
{
args: nil,
input: "{args[-1]}",
expect: "{args[-1]}",
},
} {
repl := makeArgsReplacer(test.args)
actual := repl.ReplaceKnown(test.input, "")
if actual != test.expect {
t.Errorf("Test %d: Expected: '%s' but got '%s'", i, test.expect, actual)
}
}
}
func TestSnippets(t *testing.T) {
p := testParser(`
(common) {