Open ppitonak opened 4 years ago
Thanks for the detailed report. Like you already mentioned, technically the issue is with Pipelines though using Triggers increases the risk.
One idea would be to escape anything in $()
from event bodies. Another would be for Pipelines to add some kind of escaping? On the other end of the spectrum, we could keep the behavior as is, and warn users about such potential misuse. Thoughts @gabemontero @vdemeester @wlynch ?
Minimally something to definitely highlight up top in the documentation, in both pipeline and trigger projects. And yes, as @dibyom noted here and as myself and others have noted in WG calls or other issues, security around event injection into triggers could use bolstering. We've done a few things in the space, but more is desirable.
Some thoughts from a Pod security perspective (when it is enabled) ... i.e. best practices to employ with triggers and pipelines:
Some thoughts from an authentication perspective
Some thoughts from a "granularity" perspective
On that last point, presumably, there is/are scenario(s) where being able to take advantage of bash substitution exists.
I'll defer to those who have been on the tekton project(s) longer than I to confirm/deny.
But if so, any escaping at the pipeline or trigger level would need some sort of on/off control, where administrators can then choose to employ isolation/security measures like the ones noted above as a way to mitigate these valid security concerns.
I'll defer to those who have been on the tekton project(s) longer than I to confirm/deny.
But if so, any escaping at the pipeline or trigger level would need some sort of on/off control, where administrators can then choose to employ isolation/security measures like the ones noted above as a way to mitigate these valid security concerns.
Yeah while escaping might be the correct behavior from a security standpoint, I think we do have use cases we'd want this behavior. So, I'm not sure if want to escape always either. /cc @sbwsg @bobcatfish
I've implemented a couple of different approaches here https://github.com/tektoncd/pipeline/compare/master...bigkevmcd:escape-strings-in-script
One would escape everything in the Script
element of the Task, the other would would require more explicit (using #()
) escaping.
I'll summarise the options as I see them:
On the triggers side:
shellEscape()
on strings)On the pipeline side:
#(params.name)
instead of $(params.name)
ApplyEscapedReplacements
in https://github.com/tektoncd/pipeline/blob/master/pkg/apis/pipeline/v1beta1/step_replacements.go#L23$()
but #()
meaning "don't escape this parameter.There are probably some other options I've not thought of.
@bigkevmcd SGTM.
My 2c is we should lean towards being more secure by default here and only allow unescaping if opted in if possible. My expectation is that most users (myself included) would use the $()
behavior by default, and only be burned when the input changes to something unexpected. That said, we should weigh this against the difficulty of dealing with escaping (e.g. perhaps this is something we can just document).
Given a binding:
- name: foo
value: ";${}"
and a template:
params:
- name: foo
value: $(tt.params.foo)
If the resulting request is:
params:
- name: foo
value: ';${}'
This should be relatively similar behavior to triggers today, and should protect against any direct script
injections. It would then be up to Pipelines to make sure that these params are handled properly.
Consequences I can think of:
params:
- $(tt.params.foo): bar
value: baz
I'm not sure if that's actually something we want to support anyway. (I remember talking about this in a triggers issue before, but I can't seem to find it - will update if/when I find it).
Stale issues rot after 30d of inactivity.
Mark the issue as fresh with /remove-lifecycle rotten
.
Rotten issues close after an additional 30d of inactivity.
If this issue is safe to close now please do so with /close
.
/lifecycle rotten
Send feedback to tektoncd/plumbing.
Rotten issues close after 30d of inactivity.
Reopen the issue with /reopen
.
Mark the issue as fresh with /remove-lifecycle rotten
.
/close
Send feedback to tektoncd/plumbing.
@tekton-robot: Closing this issue.
Let me see if I can clarify what we think should happen from this.
The values of all params being output in tektoncd/pipeline should be escaped to be shell-safe?
There is now a TEP that proposes adding a shell escaped version of all pipeline params: https://github.com/tektoncd/community/pull/208
@ppitonak @bigkevmcd do you think adding escaped version for pipeline params is sufficient or is there more we need to do on the Triggers side?
@dibyom I think that would be the best solution :+1:
Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale
with a justification.
Stale issues rot after an additional 30d of inactivity and eventually close.
If this issue is safe to close now please do so with /close
with a justification.
If this issue should be exempted, mark the issue as frozen with /lifecycle frozen
with a justification.
/lifecycle stale
Send feedback to tektoncd/plumbing.
Stale issues rot after 30d of inactivity.
Mark the issue as fresh with /remove-lifecycle rotten
with a justification.
Rotten issues close after an additional 30d of inactivity.
If this issue is safe to close now please do so with /close
with a justification.
If this issue should be exempted, mark the issue as frozen with /lifecycle frozen
with a justification.
/lifecycle rotten
Send feedback to tektoncd/plumbing.
Rotten issues close after 30d of inactivity.
Reopen the issue with /reopen
with a justification.
Mark the issue as fresh with /remove-lifecycle rotten
with a justification.
If this issue should be exempted, mark the issue as frozen with /lifecycle frozen
with a justification.
/close
Send feedback to tektoncd/plumbing.
@tekton-robot: Closing this issue.
/open This is a remote code execution vulnerability in Tekton. Has it been patched, and if so which versions are affected or not affected? What are steps that a Tekton user or developer can take to tell if they are vulnerable?
For anyone following along, I think I figured it out.
The problem is that when you use $(...)
in a Tekton yaml, especially within a script:
, the $(variable)
just gets replaced with the contents of variable
, and no escaping is done. Tekton actually can't escape it properly, because it doesn't know if the script:
is bash or Python or some other kind of language, so the onus is on the yaml file writer to do the escaping, or use environment variables such as in https://github.com/tektoncd/pipeline/issues/3458. You can search for instances of this using a command like:
ack --color -i -A100 -t yaml 'script:' | grep --color -E '^|\$\('
If any of the variables interpolated this way can be attacker-controlled, then the attacker can inject code into your script:
(in whatever language the script is). AFAICT the only safe way to get an attacker-controlled variable into a script is to use the environment variable trick I linked to above.
@defuse you are right, we are working on this in TEP-0099: https://github.com/tektoncd/community/pull/596
Expected Behavior
Incoming data parsed by trigger binding should be escaped so that it's not possible to execute injection attack.
In my example below, I expect to see
Hello Pavol && echo I was here on $(date +%F) and I can do whatever I want!
Actual Behavior
Steps to Reproduce the Problem
oc expose svc el-hello
Additional Info
There is basically the same problem when not using triggers at all but only plain taskrun/pipelinerun but IMHO in that case the risk of misuse/attack is quite limited.