Skip to content

envsubst: support a negative substring length instead of panicking - #1275

Open
arpitjain099 wants to merge 1 commit into
fluxcd:mainfrom
arpitjain099:fix/envsubst-negative-substr-length
Open

envsubst: support a negative substring length instead of panicking#1275
arpitjain099 wants to merge 1 commit into
fluxcd:mainfrom
arpitjain099:fix/envsubst-negative-substr-length

Conversation

@arpitjain099

Copy link
Copy Markdown

toSubstr parses the length argument and then slices with it directly:

length, err := strconv.Atoi(args[1])
...
return s[pos : pos+length]

A negative length is never considered, so ${VAR:2:-1} builds a backwards slice and panics:

panic: runtime error: slice bounds out of range [2:1]

That is reachable straight through the public API, not just the helper:

Eval("${VAR:2:-1}", func(string) (string, bool) { return "hello world", true })

which matters because with post-build substitution the template is the manifest text, so the expression that crashes the process can come from a Kustomization rather than from the operator's own environment.

The rest of this file goes out of its way to match bash ("bash returns the string if the position cannot be parsed"), and bash has had negative lengths since 4.2: they count back from the end of the string, and the expression is rejected when the end lands before the offset. I checked the cases against bash 5 rather than going from the manual:

$ VAR="hello world"; echo "[${VAR:2:-1}]"; echo "[${VAR:0:-3}]"; echo "[${VAR: -4:-1}]"; echo "[${VAR:8:-8}]"
[llo worl]
[hello wo]
[orl]
bash: line 1: -8: substring expression < 0

So this handles the negative length the same way, returning an empty string for the case bash errors on, since these helpers have no error channel. Positive lengths take exactly the same path as before.

Four cases added to Test_substr. On the unmodified tree the first of them panics and takes the test binary down; with the change go test ./... passes across the envsubst module.

toSubstr parsed the length argument and then sliced s[pos : pos+length]
without considering a negative length, so ${VAR:2:-1} produced a
backwards slice and panicked with

  slice bounds out of range [2:1]

The template is the manifest text, so a Kustomization using post-build
substitution can take down the controller with a substitution expression
alone.

bash counts a negative length back from the end of the string, so
${VAR:2:-1} on "hello world" is "llo worl", and it rejects the
expression when the end lands before the offset. Match that, returning an
empty string for the rejected case since these helpers have no error
channel. Verified against bash 5.

Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
@arpitjain099
arpitjain099 requested a review from a team as a code owner August 3, 2026 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant