Skip to content

Commit 538955f

Browse files
ogulcanaydogantekton-robot
authored andcommitted
fix: use non-expandable here-string for windows script placement
The place-scripts init container's Windows path wrapped script content in an expandable here-string (@"..."@), which PowerShell terminates on any "@ appearing on its own line within the content. A script whose body contains that sequence (e.g. via $(params.x) substitution) would end the here-string early, turning the remaining content into PowerShell commands executed in the init container. Switched to the non-expandable form (@'...'@), matching how the Linux path already avoids the equivalent issue with a single-quoted heredoc. Only a '@ line on its own can now terminate the string, which is far less likely to appear in script content. This is defense-in-depth, not a fix for the underlying $(params.x) raw substitution design (reported via a security advisory, closed as not a vulnerability: same trust domain as the existing Linux script injection class). Signed-off-by: Ogulcan Aydogan <ogulcanaydogan@gmail.com>
1 parent 0f6f063 commit 538955f

2 files changed

Lines changed: 53 additions & 16 deletions

File tree

‎pkg/pod/script.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,9 @@ func placeScriptInContainer(script, scriptFile string, c *corev1.Container, init
179179
// script file in a known location in the scripts volume.
180180
if requiresWindows {
181181
command, args, script, scriptFile := extractWindowsScriptComponents(script, scriptFile)
182-
initContainer.Args[1] += fmt.Sprintf(`@"
182+
initContainer.Args[1] += fmt.Sprintf(`@'
183183
%s
184-
"@ | Out-File -FilePath %s
184+
'@ | Out-File -FilePath %s
185185
`, script, scriptFile)
186186

187187
c.Command = command

‎pkg/pod/script_test.go‎

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -781,17 +781,17 @@ no-shebang`,
781781
Name: "place-scripts",
782782
Image: images.ShellImageWin,
783783
Command: []string{"pwsh"},
784-
Args: []string{"-Command", `@"
784+
Args: []string{"-Command", `@'
785785
#!win pwsh -File
786786
script-1
787-
"@ | Out-File -FilePath /tekton/scripts/script-0-9l9zj
788-
@"
787+
'@ | Out-File -FilePath /tekton/scripts/script-0-9l9zj
788+
@'
789789
#!win powershell -File
790790
script-3
791-
"@ | Out-File -FilePath /tekton/scripts/script-2-mz4c7.ps1
792-
@"
791+
'@ | Out-File -FilePath /tekton/scripts/script-2-mz4c7.ps1
792+
@'
793793
no-shebang
794-
"@ | Out-File -FilePath /tekton/scripts/script-3-mssqb.cmd
794+
'@ | Out-File -FilePath /tekton/scripts/script-3-mssqb.cmd
795795
`},
796796
VolumeMounts: []corev1.VolumeMount{writeScriptsVolumeMount, binMount},
797797
SecurityContext: WindowsSecurityContext,
@@ -863,18 +863,18 @@ sidecar-1`,
863863
Name: "place-scripts",
864864
Image: images.ShellImageWin,
865865
Command: []string{"pwsh"},
866-
Args: []string{"-Command", `@"
866+
Args: []string{"-Command", `@'
867867
#!win pwsh -File
868868
script-1
869-
"@ | Out-File -FilePath /tekton/scripts/script-0-9l9zj
870-
@"
869+
'@ | Out-File -FilePath /tekton/scripts/script-0-9l9zj
870+
@'
871871
#!win powershell -File
872872
script-3
873-
"@ | Out-File -FilePath /tekton/scripts/script-2-mz4c7.ps1
874-
@"
873+
'@ | Out-File -FilePath /tekton/scripts/script-2-mz4c7.ps1
874+
@'
875875
#!win pwsh -File
876876
sidecar-1
877-
"@ | Out-File -FilePath /tekton/scripts/sidecar-script-0-mssqb
877+
'@ | Out-File -FilePath /tekton/scripts/sidecar-script-0-mssqb
878878
`},
879879
VolumeMounts: []corev1.VolumeMount{writeScriptsVolumeMount, binMount},
880880
SecurityContext: WindowsSecurityContext,
@@ -933,10 +933,10 @@ sidecar-1`,
933933
Name: "place-scripts",
934934
Image: images.ShellImageWin,
935935
Command: []string{"pwsh"},
936-
Args: []string{"-Command", `@"
936+
Args: []string{"-Command", `@'
937937
#!win python
938938
sidecar-1
939-
"@ | Out-File -FilePath /tekton/scripts/sidecar-script-0-9l9zj
939+
'@ | Out-File -FilePath /tekton/scripts/sidecar-script-0-9l9zj
940940
`},
941941
VolumeMounts: []corev1.VolumeMount{writeScriptsVolumeMount, binMount},
942942
SecurityContext: WindowsSecurityContext,
@@ -965,3 +965,40 @@ sidecar-1
965965
t.Errorf("Wanted 1 sidecar, got %v", len(gotSidecars))
966966
}
967967
}
968+
969+
// TestConvertScripts_Windows_LiteralHereStringTerminator guards against a script body that
970+
// contains a literal `"@` line breaking out of the generated PowerShell here-string. The
971+
// expandable here-string (`@"..."@`) treats `"@` on its own line as its terminator, so a
972+
// script containing that sequence (e.g. from `$(params.x)` substitution) would end the
973+
// here-string early and turn the remaining script content into PowerShell commands run in
974+
// the init container. Using the non-expandable form (`@'...'@`) means only a `'@` line on
975+
// its own can terminate it, so a literal `"@` line is passed through as inert script content.
976+
func TestConvertScripts_Windows_LiteralHereStringTerminator(t *testing.T) {
977+
names.TestingSeed()
978+
979+
gotInit, _, _ := convertScripts(images.ShellImage, images.ShellImageWin, []v1.Step{{
980+
Script: `#!win pwsh -File
981+
echo before
982+
"@
983+
echo after`,
984+
Image: "step-1",
985+
}}, []v1.Sidecar{}, nil, SecurityContextConfig{SetSecurityContext: true, SetReadOnlyRootFilesystem: true})
986+
987+
wantInit := &corev1.Container{
988+
Name: "place-scripts",
989+
Image: images.ShellImageWin,
990+
Command: []string{"pwsh"},
991+
Args: []string{"-Command", `@'
992+
#!win pwsh -File
993+
echo before
994+
"@
995+
echo after
996+
'@ | Out-File -FilePath /tekton/scripts/script-0-9l9zj
997+
`},
998+
VolumeMounts: []corev1.VolumeMount{writeScriptsVolumeMount, binMount},
999+
SecurityContext: WindowsSecurityContext,
1000+
}
1001+
if d := cmp.Diff(wantInit, gotInit); d != "" {
1002+
t.Errorf("Init Container Diff %s", diff.PrintWantGot(d))
1003+
}
1004+
}

0 commit comments

Comments
 (0)