
हेल्म प्लगइन इंस्टॉलेशन में पाथ ट्रैवर्सल भेद्यता (CVE-2026-35204) प्रदर्शित करने वाला प्रूफ-ऑफ-कॉन्सेप्ट, क्राफ्टेड प्लगइन मेटाडेटा के माध्यम से मनमानी फ़ाइल लेखन की अनुमति देता है।
यह भंडार CVE-2026-35204 के लिए एक PoC प्रस्तुत करता है
"Helm Kubernetes चार्ट्स के लिए एक पैकेज मैनेजर है। 4.0.0 से 4.1.3 तक, एक विशेष रूप से तैयार किया गया Helm प्लगइन, जब स्थापित या अद्यतन किया जाता है, तो Helm प्लगइन की सामग्री को एक मनमाना फ़ाइल सिस्टम स्थान पर लिख देगा। इसे रोकने के लिए, सत्यापित करें कि Helm प्लगइन के plugin.yaml में version: फ़ील्ड में POSIX डॉट-डॉट पथ विभाजक अर्थात "/../" शामिल नहीं है। यह भेद्यता 4.1.4 में ठीक की गई है।"
यह PoC प्रदर्शित करता है कि metadata.Version का उपयोग प्लगइन संग्रह का पथ बनाने के लिए किया जाता है, जिससे पथ ट्रैवर्सल संभव होता है और डाउनलोड किया गया plugin.tgz इच्छित प्लगइन निर्देशिका के बाहर लिखा जाता है। प्लगइन सामग्री अभी भी स्थापना से पहले निर्दिष्ट कैश निर्देशिका में निकाली जाती है, इसलिए यह PoC मनमाना निष्कर्षण या मनमाना होस्ट फ़ाइल अधिलेखन प्रदर्शित नहीं करता है।
Helm प्लगइन इंस्टॉलर में चार कार्यान्वयनों (HTTP, local, VCS और OCI) के साथ एक इंटरफ़ेस है। यह PoC HTTP इंस्टॉलर पर केंद्रित है। HTTP/OCI इंस्टॉलरों के विपरीत, VCS इंस्टॉलर metadata.Version से tarball पथ का निर्माण बिल्कुल नहीं करता है। यहाँ एक कोड ब्लॉक है जो tarballPath तैयार करता है:
filename := fmt.Sprintf("%s-%s.tgz", metadata.Name, metadata.Version)
tarballPath := helmpath.DataPath("plugins", filename)
जहाँ metadata.Version वह चर है जिसे हम plugin.yaml में नियंत्रित करते हैं। भेद्यता को ट्रिगर करने के लिए, आपको अपने तैयार किए गए प्लगइन को .tgz संग्रह में पैकेज करना होगा, क्योंकि इसका metadata.Version वही है जो plugin.ExtractTgzPluginMetadata द्वारा निकाला जाता है और HTTP/OCI/local इंस्टॉलर के माध्यम से डाउनलोड किया जाता है। इसलिए, पथ ट्रैवर्सल प्राप्त करने के लिए, हम http_installer का उपयोग कर सकते हैं, जो एक वेब सर्वर द्वारा परोसे गए संग्रह के रूप में प्लगइन प्राप्त करता है।
नीचे दिए गए उदाहरण में, helm बाइनरी को लॉगिंग संदेशों को सक्षम करने के लिए मैन्युअल रूप से पुनर्निर्मित किया गया था, जहाँ आप दो अलग-अलग डेटा प्रवाह देख सकते हैं। पहला सही संस्करण नाम के साथ प्लगइन स्थापना है। दूसरा वह प्लगइन स्थापना है जिसके संस्करण नाम में डॉट-डॉट पथ विभाजक हैं:
./helm plugin install http://0.0.0.0:8000/evil.tar.gz
Verifying plugin signature...
WARNING: No provenance file found for plugin. Plugin is not signed and cannot be verified.
filename -> evil-2.2.2.tgz
tarballPath -> /home/s0m3body/.local/share/helm/plugins/evil-2.2.2.tgz
i.CacheDir -> /home/s0m3body/.cache/helm/plugins/http-0.0.0.0-8000-evil.tar.gz
i.Path() -> /home/s0m3body/.local/share/helm/plugins/evil
Installed plugin: evil
./helm plugin install http://127.0.0.1:8000/evil.tar.gz
Verifying plugin signature...
WARNING: No provenance file found for plugin. Plugin is not signed and cannot be verified.
filename -> evil-../../../../../../.ssh/pwn3d.tgz
tarballPath -> /home/s0m3body/.ssh/pwn3d.tgz
i.CacheDir -> /home/s0m3body/.cache/helm/plugins/http-127.0.0.1-8000-evil.tar.gz
i.Path() -> /home/s0m3body/.local/share/helm/plugins/evil
Installed plugin: evil
रनटाइम ट्रेस दर्शाते हैं कि पथ ट्रैवर्सल केवल उस स्थान को प्रभावित करता है जहाँ डाउनलोड किया गया प्लगइन संग्रह रखा जाता है, जो मूलतः HELM_PLUGINS env चर है। कैश (i.CacheDir) और अंतिम निष्कर्षण (i.Path()) अपरिवर्तित रहते हैं। इसे ध्यान में रखते हुए, हम अस्थायी संग्रह गंतव्य और उसके नाम में हेरफेर कर सकते हैं जिसके परिणामस्वरूप फ़ाइल लेखन होता है।
आपको कुछ भी चलाने या पोस्ट इंस्टॉल वेबहुक का उपयोग करने की आवश्यकता नहीं है, भेद्यता को ट्रिगर करने के लिए साधारण प्लगइन स्थापना पर्याप्त है।
HTTP इंस्टॉलर के अपने विश्लेषण के दौरान, मैंने देखा कि संग्रह निष्कर्षण i.CacheDir में होता है, जबकि स्थापना (fs.CopyDir) i.CacheDir से i.Path() में फ़ाइलों की प्रतिलिपि बनाती है। मुझे कोई कोड पथ नहीं मिला जहाँ ट्रैवर्सल-प्रभावित tarballPath संग्रह सामग्री को प्रभावित करता है। इसलिए, विश्लेषित रनटाइम ट्रेसिंग के आधार पर, संग्रह निष्कर्षण गंतव्य ट्रैवर्सल-नियंत्रित tarballPath से स्वतंत्र है।
परामर्श में स्थापना और अद्यतन दोनों का उल्लेख है। HTTP/local/VCS इंस्टॉलरों के लिए, Update() लागू नहीं किया गया है; OCI इंस्टॉलर पिछले प्लगइन को हटाने के बाद Install() को आमंत्रित करके अद्यतन को लागू करता है।
यहाँ HTTP इंस्टॉलर से Update() विधि है:
func (i *HTTPInstaller) Update() error {
return fmt.Errorf("method Update() not implemented for HttpInstaller")
}
भेद्यता को कम करने के लिए, isValidSemver फ़ंक्शन जोड़ा गया, जिसे अब metadata.go के अंदर Validate() कॉल किए जाने पर बुलाया जाता है।
"github.com/Masterminds/semver/v3"
func isValidSemver(v string) bool {
_, err := semver.NewVersion(v)
return err == nil
}
if m.Version != "" && !isValidSemver(m.Version) {
errs = append(errs, fmt.Errorf("invalid plugin version %q: must be valid semver", m.Version))
}
जैसा कि आप देख सकते हैं, यदि संस्करण एक मान्य semver नहीं है (और ../../../../ नहीं है), तो हमें दुष्ट helm प्लगइन स्थापना की प्रक्रिया में एक त्रुटि प्राप्त होगी।
PoC चलाने के लिए आप scripts/pos.sh स्क्रिप्ट का उपयोग कर सकते हैं:
./scripts/poc.sh
जिसके परिणामस्वरूप कुछ इस प्रकार होगा:

MIT