22 comments

[ 4.8 ms ] story [ 39.8 ms ] thread
That description seems really unclear, like how can `Chart.lock` be a symlink to a `.bashrc`?

Is the vulnerability that you ship a chart with `Chart.lock -> ../.bashrc`, and then helm writes to `Chart.lock`?

Why is the fix specific to Chart.lock (https://github.com/helm/helm/commit/76fdba4c8c2a4829a6b7abb4...), wouldn't the fix be instead that "A chart cannot contain any symlinks outside of its root"?

If we're being honest, YAML is one of the dumbest ideas of the last 20 years to have proliferated. How we got from XML to here I cannot comprehend.

This is not the first RCE involving YAML and it won't be the last.

Wondering how this kind of thing can be automatically discovered by an LLM. Anyone have any experience?
What is the attack scenario here? Where are the security boundaries? How does the attacker gets their repository with a symlink in it to the victim? Is Helm typically run as a privileged user? How would this work? And why doesn't the vulnerability description give answers to these questions?
> What is the attack scenario here?

Given the details in the article, I think even something as simple a templating a chart from a repository might be vuln., but it likely depends on a lot of exact specifics.

> Where are the security boundaries?

I expect templating does not result in LCE.

> How does the attacker gets their repository with a symlink in it to the victim?

The attacker owns the repository. They can serve whatever maliciousness in it they want. But should templating a malicious chart result in LCE?

> Is Helm typically run as a privileged user?

Enough so, yes, because the rendered result is often pushed to a k8s cluster. "Privileged" here might not be "root", but it might be "this user has k8s API access".

Imagine, e.g., that the attacker's LCE here might be "push ~/.kube to attacker".

> And why doesn't the vulnerability description give answers to these questions?

Familiarity with the tools involved is an normal assumption.

The original vulnerability description is not worded very well, here's my understanding of what's going on:

1. Attacker crafts a malicious Chart.yaml containing arbitrary code

2. Replaces Chart.lock with a symlink pointing to a sensitive file (like .bashrc or other startup scripts)

3. When you run helm dependency update, Helm processes the malicious Chart.yaml and writes the payload to whatever file the symlink targets

4. Code executes when the targeted file is next used (e.g., opening a new shell)

Why This Works: Helm follows the symlink during the dependency update process without validating the target, allowing arbitrary file writes outside the intended chart directory.

But I thought security vulnerabilities couldn't happen in memory-safe languages!
I would argue that not sanitising strings is analogous to a form of memory unsafety. You take as an input, an opaque blob of bytes that you then pass on to a myriad of other libraries and pieces of code. Nothing is captured in the types other than "String". Mainstream programming languages need to make it easier to define new types and parse strings into them. Rust is very promising in this area, as it features algebraic data types.
So the attack vector is:

- You have access to my file system

- You have access to the helm repository

You place malicious binaries outside the helm directory. Helm will now execute malicious code through the helm chart pointing outside the helm directory.

Don't I have already bigger problems if you have access to my file system to place there malicious code?

Is the danger here that one can get an execute permission? But if you can manipulate my helm chart why can you not also place the malicious code in the helm directory?

> But if you can manipulate my helm chart why can you not also place the malicious code in the helm directory?

If you can manipulate my helm chart, why not just do the RCE directly in my kubernetes cluster or whatever?

As an aside, all these tools like aider, claude desktop ask for shell access to run codes.

Allowing LLMs to generate charts and what not via shell execution is a bad idea.

Pretty cool and nice find. I already have a "malicious" Chart.yaml in mind for this attack just based on the description of vuln.

Fortunately, my dotfiles are managed with nix so trying to write to those files on a read only partition will raise many red flags for me.

I don't use bash, but maybe should write a dummy .bashrc (and other start up script equivalents for fish) as some sort of canary.

If I happen to overlook the malicious shell script crafted in a dependency on helm chart, I would get nasty errors that a process was trying to write to a read only file.

Helm is an abomination, as the whole idea of using a text template engine to generate YAML is. And this vulnerability adds insult to injury ;)

Sorry, just can't really recover from trauma of counting spaces and messing up newlines, etc. when writing Helm templates. You know, Lisp "sucks" because "you need to count parenthesis" (you actually don't), yet Helm is a widely accepted technology where you need to count spaces for (n)indent ;)

Yeah, vi has supported % as "jump between matching parenthesis" since it's original release in the 1970s, and vim by default will do simple parenthesis matching and highlighting, I don't see why everyone is so scared of touching lisp for these reasons with modern editors (if your editor doesn't support either of the above... maybe it's not modern enough?)
This isn't a uniquely helm thing though, they mostly use modified go templating. Lots of other things do this with yaml as well.
The funny thing is helm is as good or bad as what you make it. When folks complain about helm they are actually complaining about their own self created charts or poor selection of charts they install.
I don’t think there is a lot of overlap between people who say lisp sucks because of the parens and people who are fine with using a template to generate yaml.
I'm a dev that jumped to devops and one of my pet peeves will always be the lengths devops engineers go to avoid using a real programming language. Instead of interacting with all these APIs through python, ruby, lua, go, whatever they would rather build hodgepodge systems in bash, coreutils, curl (or wget. or both!) and jq (which is the worst). Or in the case of helm, just creating a half yaml/half Go SDK for generating YAML.

Even the helm infrastructure that I work in is completely wrapped in custom shell scripts that call all sorts of other commands to populate helm variables.

But yeah it's silly that helm templates require all sorts of {{ indent | 4 }} type incantations when the final YAML output is just sent through some kind of toJSON anyway.

Something like kustomize was a better approach, where resources are templates semantically.

Though it's lacking in several ways, like good destroy functionality.

I like wrapping with kapp for this. However kustomize still skips hooks if you inflate a chart that uses them and there is value in discoverability of helm apps installed with clear versioning

      kustomize build | kapp deploy -a my-app -y -f -