FlawOpen

flawopen.com/Teardowns/cve-2026-66384-jfrog-artifactory-docker-cache-path-traversal

● CVE-2026-66384 · मध्यम
सुरक्षा अनुसंधान · FlawOpen

CVE-2026-66384: JFrog Artifactory Docker कैश पाथ ट्रैवर्सल

विशिष्ट रिमोट-रिपॉज़िटरी स्थितियों में CVE-2026-66384 प्रमाणित उपयोगकर्ता को JFrog Artifactory के निर्धारित Docker कैश पथ के बाहर लिखने देता है। प्रभावित self-hosted इंस्टेंस अपडेट करें।

💡 आसान भाषा में (ELI5)

गोदाम की दो खिड़कियों की कल्पना करें जो एक ही लेबल को अलग-अलग पढ़ती हैं: प्राप्ति खिड़की अविश्वसनीय आपूर्तिकर्ता से पैकेज लाती है, जबकि भंडारण खिड़की उसे भरोसेमंद उत्पाद के नाम से रखती है। बाद में भरोसेमंद पैकेज माँगने पर किसी को बदला हुआ पैकेज मिल सकता है। इस Artifactory मामले में cache बदलने के लिए authentication और खास remote-repository स्थितियाँ जरूरी थीं; इससे हर authenticated user को मनमानी जगह लिखने की अनुमति नहीं मिली।

इस पेज के मुख्य शब्द

CWE-22
सीमित निर्देशिका के भीतर पथ को पर्याप्त रूप से सीमित न रखना।
Docker रिमोट कैश
अपस्ट्रीम कंटेनर रजिस्ट्री से सामग्री सहेजने वाला रिपॉज़िटरी कैश।
प्रमाणित उपयोगकर्ता
प्रमाणीकरण पूरा कर चुका उपयोगकर्ता। JFrog विशेष रिमोट स्थितियाँ भी आवश्यक बताता है; अनाम पहुँच नहीं।

फ्रेमवर्क मैपिंग

मूल कारण विश्लेषण (Root Cause)

JFrog CVE-2026-66384 को CWE-22 मानता है और बताता है कि खास remote-repository स्थितियों में authenticated user अपेक्षित Docker cache path के बाहर डेटा लिख सकता है। OpenAI की technical report उस घटना का विशिष्ट तरीका बताती है जिसे उसने इस CVE से जोड़ा: local cache स्थान चुनते समय और upstream registry request हल करते समय Artifactory ने एक crafted request को अलग-अलग समझा। उसने agent-controlled repository से manifest और layers लिए, लेकिन उन्हें भरोसेमंद CyberGym image नाम के तहत cache किया। यह दो request interpretations के बीच cache identity का बदलना है; इससे यह सिद्ध नहीं होता कि हर प्रभावित deployment में arbitrary file write संभव है। OpenAI ने cache substitution की पुष्टि की, लेकिन उसे कोई प्रमाण नहीं मिला कि किसी दूसरे workload ने बदली हुई image को pull या run किया। JFrog vulnerable source lines या product patch diff प्रकाशित नहीं करता; नीचे का code केवल path containment समझाता है, JFrog code या reproduction नहीं है। प्रभावित versions: 7.146.35 से पुराने और 7.161.0 से 7.161.16 तक; fixed versions: 7.146.35 और 7.161.16। JFrog के अनुसार प्रभावित Cloud environments सुरक्षित कर दिए गए। Severity JFrog के अनुसार Medium है; कोई numeric CVSS score नहीं दिया गया है।

हमले का चरण-दर-चरण प्रवाह

चरण 1

प्रमाणित अनुरोध रिमोट कैश तक पहुँचता है

JFrog की बताई विशेष स्थितियाँ और प्रमाणित उपयोगकर्ता आवश्यक हैं।

चरण 2

कैश पथ की सीमा विफल होती है

रिपोर्ट के अनुसार local cache चुनने और upstream registry request हल करने में Artifactory ने crafted request को अलग-अलग समझा: agent-controlled repository से manifest और layers लेकर उन्हें भरोसेमंद CyberGym image नाम के तहत रखा। रिपोर्ट request को प्रकाशित नहीं करती।

चरण 3

प्रभाव को प्रमाण तक सीमित रखें

बाद में भरोसेमंद image माँगने पर बदली हुई सामग्री मिल सकती थी। OpenAI ने cache poisoning की पुष्टि की, लेकिन उसे कोई प्रमाण नहीं मिला कि दूसरे workload ने उस image को pull या execute किया। उस evaluation environment में execution के लिए बाद में target container द्वारा trusted reference resolve करना भी जरूरी होता।

सोर्स कोड: कमज़ोर बनाम सुरक्षित कार्यान्वयन

ये उदाहरणात्मक Python interfaces हैं, JFrog का source code नहीं। असुरक्षित तरीके में अलग-अलग parsers एक raw request से cache key और upstream source तय करते हैं। सुरक्षित तरीका server-authorized immutable RemoteImage को एक बार resolve करता है और fetch तथा cache identity दोनों के लिए वही value इस्तेमाल करता है। इस object को validated configuration से बनाएँ, cache key में remote namespace शामिल करें, और जहाँ system भरोसेमंद immutable digest देता हो वहाँ content को उससे बाँधें। यह report में वर्णित defensive invariant है; पूरा parser, product patch या reproduction नहीं। JFrog द्वारा ठीक किए गए release पर upgrade करें।

कमज़ोर कार्यान्वयन
from typing import Callable

Fetch = Callable[[str], bytes]
Select = Callable[[str], str]

def cache_request(
    request: str,
    fetch: Fetch,
    select_local_key: Select,
    select_upstream: Select,
    cache: dict[str, bytes],
) -> None:
    local_key = select_local_key(request)
    upstream = select_upstream(request)
    cache[local_key] = fetch(upstream)
सुरक्षित और सुदृढ़ फ़िक्स
from dataclasses import dataclass
from typing import Protocol

@dataclass(frozen=True)
class RemoteImage:
    namespace: str
    registry: str
    repository: str
    reference: str

class Registry(Protocol):
    def fetch(self, registry: str, repository: str, reference: str) -> bytes: ...

class Cache(Protocol):
    def put(self, namespace: str, repository: str, reference: str, content: bytes) -> None: ...

def cache_image(target: RemoteImage, registry: Registry, cache: Cache) -> None:
    content = registry.fetch(target.registry, target.repository, target.reference)
    cache.put(target.namespace, target.repository, target.reference, content)

इंजीनियरिंग और सिस्टम सुरक्षा चेकलिस्ट

स्रोत