flawopen.com/Incidents/rubygems-cdn-cache-api-key-leak-july-2026
RubyGems: CDN कैश से API कुंजी का खुलासा
gzip/CDN कैश दोष से RubyGems की पुरानी कुंजियाँ उजागर हुईं। यहाँ सुधार और रिकवरी के कदम हैं; अलग पैकेज अभियान में AI की भूमिका विवादित है।
एक ऐसे काउंटर की कल्पना करें जो हर सत्यापित ग्राहक के लिए नई मास्टर चाबी बनाता है, लेकिन पैकिंग मशीन द्वारा लिफाफे का लेबल बदलने के कारण उसकी प्रति साझा ट्रे में रख देता है। उसी काउंटर पर अगला व्यक्ति बिना पहचान दिखाए पिछले ग्राहक की चाबी उठा सकता है। सुधार साझा कैश को निजी उत्तर रखने से रोकता है और प्राधिकरण के आधार पर उत्तर अलग करता है।
इस पेज के मुख्य शब्द
Legacy API key- RubyGems की लंबे समय तक मान्य रहने वाली व्यापक gem-प्रबंधन अनुमति वाली कुंजी। सलाह के अनुसार इससे नया gem संस्करण प्रकाशित करना, संस्करण हटाना, मालिक जोड़ना और webhook या trusted-publisher सेटिंग बदलना संभव था; इससे खाते में लॉगिन या प्रकाशित रिलीज़ बदलना संभव नहीं था।
Shared cache / POP- CDN का Point of Presence (POP) उत्तर को बाद के अनुरोधों के लिए सहेजता है। यदि संवेदनशील जानकारी वाला प्रमाणित उत्तर निजी कैश नीति और प्राधिकरण-आधारित कैश कुंजी के बिना साझा हो, तो दूसरा कॉलर वही उत्तर पा सकता है।
Compression middleware- RubyGems के अनुसार Accept-Encoding: gzip ने Rack middleware के बीच ऐसी प्रक्रिया शुरू की जिससे उत्तर में private निर्देश और Vary: Authorization नहीं रहे। gzip के बिना साधारण अनुरोधों में वही हेडर व्यवहार नहीं था।
CWE-200 and CWE-524- GitHub Security Advisory
CWE-200को संवेदनशील जानकारी के खुलासे औरCWE-524को संवेदनशील जानकारी रखने वाले कैश के उपयोग से जोड़ता है। ये खुलासे और कैश सीमा को दर्शाते हैं; कोई CVE जारी नहीं हुआ। RubyGems package-flood attribution- RubyGems ने मई 2026 में पैकेज प्रकाशित करने के दुरुपयोग की पुष्टि की, पर यह निर्धारित नहीं कर सकी कि AI एजेंटों ने उन्हें बनाया या प्रकाशित किया था। इस अभियान को कैश दोष से अलग रखें; स्रोत यह नहीं दिखाते कि अभियान ने कुंजियाँ उजागर कीं।
फ्रेमवर्क मैपिंग
घटना का समयक्रम (Timeline)
RubyGems 3.2.0 ने सामान्य gem signin प्रक्रिया को सीमित दायरे वाली कुंजी बनाने में बदला, लेकिन सर्वर ने पुराना GET मार्ग चालू रखा।
Truffle Security ने कैश समस्या RubyGems को बताई।
RubyGems ने उत्तर-हेडर सुधार लागू किया और Fastly से प्रभावित कैश ऑब्जेक्ट हटाए।
RubyGems ने GHSA-9j48-x3c3-mrp2 प्रकाशित किया और कहा कि सभी पुरानी कुंजियाँ रद्द कर दी गईं। GHSA का स्कोर 7.3 High है; RubyGems ने पर्यावरण सहित कुल स्कोर 7.2 High बताया।
RubyGems ने मई के पैकेज-प्रकाशन अभियान का अलग विवरण दिया और कहा कि इसे AI एजेंटों से जोड़ना संभव नहीं है।
हमले का चरण-दर-चरण प्रवाह
पुराना मार्ग क्रेडेंशियल बनाता है
/api/v1/api_key पर प्रमाणित GET अनुरोध व्यापक अनुमति वाली पुरानी API कुंजी बनाकर लौटाता है। RubyGems कहता है कि संस्करण 3.2.0 से पुराने gem क्लाइंट इस मार्ग का उपयोग करते थे; नए क्लाइंट सीमित कुंजियों पर चले गए, फिर भी सर्वर ने यह मार्ग बनाए रखा।
gzip हेडर-प्रक्रिया बदलता है
क्लाइंट gzip मांगता है। RubyGems इस कैश व्यवहार को Rack::Deflater और Rack::ETag की परस्पर प्रक्रिया से जोड़ता है: संपीड़ित उत्तर में केवल साधारण Cache-Control: no-cache रह गया, private और Vary: Authorization नहीं थे।
CDN प्रमाणित उत्तर दोबारा उपयोग करता है
प्रभावित Fastly विन्यास में उत्तर किसी POP पर एक घंटे तक रखा जा सकता था। कैश कुंजी Authorization के अनुसार कॉलरों को अलग नहीं करती थी, इसलिए edge अगली पहचान की पुष्टि के लिए RubyGems से संपर्क किए बिना पिछला उत्तर लौटा सकता था।
दूसरे कॉलर को कुंजी मिलती है
उसी POP से होकर उसी कैश वैरिएंट वाला अनुरोध पिछले उपयोगकर्ता की कुंजी पा सकता था। RubyGems कहता है कि यह लॉगिन के दौरान अनजाने में हो सकता था; उसने कैश उत्तर को बिना प्रमाणीकरण पढ़े जाने की संभावना भी बताई। उपलब्ध लॉग में दुर्भावनापूर्ण उपयोग नहीं मिला, लेकिन वे सीमित समय को कवर करते थे।
कुंजी की अनुमति प्रभाव सीमित करती है
लीक हुई पुरानी कुंजी से नए gem संस्करण प्रकाशित करना, संस्करण हटाना, मालिक बदलना और webhook या trusted-publisher सेटिंग बदलना संभव था। प्रकाशित रिलीज़ बदली नहीं जा सकती थीं। RubyGems के अनुसार UI और API दोनों पर MFA मांगने से केवल कुंजी के आधार पर publish, yank और मालिक बदलने की कार्रवाई रुकती है।
सुधार साझा उपयोग रोकता और कुंजियाँ रद्द करता है
पैच Cache-Control: private, no-store, Surrogate-Control: max-age=0 और Vary: Authorization जोड़ता है। RubyGems ने Fastly कैश साफ किया, पुरानी कुंजियाँ रद्द कीं और GET साइन-इन मार्ग बंद किया। वह सीमित कुंजियों, API MFA और CI में trusted publishing की सलाह देता है।
सोर्स कोड: कमज़ोर बनाम सुरक्षित कार्यान्वयन
असुधारे गए कंट्रोलर अंश को RubyGems के सार्वजनिक सुधार में हटाई गई पंक्तियों से पुनर्निर्मित किया गया है; असुरक्षित कैश हेडर Rack middleware के मेल से बने थे, इस action द्वारा सार्वजनिक कैश नीति तय करने से नहीं। सुरक्षित callback और हेडर commit d3d11c0 से मेल खाते हैं। private, no-store साझा भंडारण रोकता है, Surrogate-Control proxy caching रोकता है और Vary: Authorization उन कैश में भी उत्तर अलग करता है जो फिर भी उन्हें रखें। यह स्रोत-कोड विश्लेषण है, अनुरोध चलाने की विधि या स्वतंत्र पैच नहीं; विक्रेता का पूरा सुधार लागू करें और पुराने कैश हटाएँ।
class Api::V1::ApiKeysController < Api::BaseController
include ApiKeyable
# सुधार से पहले के कंट्रोलर में deny_shared_cache कॉलबैक नहीं था।
def show
authenticate_or_request_with_http_basic do |username, password|
user = User.authenticate(username.strip, password)
check_mfa(user) do
key = generate_unique_rubygems_key
api_key = user.api_keys.build(
legacy_key_defaults.merge(hashed_key: hashed_key(key))
)
save_and_respond(api_key, key)
end
end
end
end
class Api::V1::ApiKeysController < Api::BaseController
include ApiKeyable
before_action :deny_shared_cache
def show
authenticate_or_request_with_http_basic do |username, password|
user = User.authenticate(username.strip, password)
check_mfa(user) do
key = generate_unique_rubygems_key
api_key = user.api_keys.build(
legacy_key_defaults.merge(hashed_key: hashed_key(key))
)
save_and_respond(api_key, key)
end
end
end
end
# सुधार में Api::BaseController में जोड़ा गया।
def deny_shared_cache
response.headers["Cache-Control"] = "private, no-store"
response.headers["Surrogate-Control"] = "max-age=0"
response.headers["Vary"] = [response.headers["Vary"], "Authorization"].compact_blank.join(", ")
end
इंजीनियरिंग और सिस्टम सुरक्षा चेकलिस्ट
- ✓यदि आपने RubyGems.org की पुरानी क्रेडेंशियल कुंजियाँ इस्तेमाल की थीं, उन्हें बदलें: RubyGems ने सभी पुरानी कुंजियाँ रद्द कीं। संस्करणों, अनपेक्षित हटावों, मालिकों, trusted publishers और webhooks की जाँच करें; यह न मानें कि मौजूदा रिलीज़ फिर से लिखी गईं।
- ✓केवल जरूरी gem और कार्यों की अनुमति वाली API कुंजी रखें, UI और API दोनों पर MFA चालू करें और CI के लंबे समय तक चलने वाले secrets के बजाय trusted publishing/OIDC अपनाएँ। जाँचें कि प्रत्येक workflow केवल अपेक्षित gem प्रकाशित कर सके।
- ✓CDN के पीछे प्रमाणित उत्तरों या secrets के लिए origin पर Cache-Control: private, no-store सेट करें, surrogate cache बंद करें और प्राधिकरण के हर आयाम को Vary/कैश कुंजी में शामिल करें। वास्तविक CDN पथ पर compression चालू और बंद दोनों स्थितियों में परीक्षण करें।
- ✓Accept-Encoding: gzip के साथ credentials endpoint पर अनुरोध करने वाला integration test जोड़ें; private, no-store, Surrogate-Control: max-
age=0और Vary: Authorization की जाँच हो। यह भी जाँचें कि दूसरी पहचान साझा edge cache से पहली प्रतिक्रिया न पा सके। - ✓कैश रिसाव ठीक करते समय नए secrets देने से पहले कैश ऑब्जेक्ट हटाएँ; पुराने लॉग को सीमित साक्ष्य मानें, रिसाव न होने का प्रमाण नहीं। जाँच योग्य समय-सीमा दर्ज करें।
- ✓आरोपण सही रखें: RubyGems ने मई 2026 के अभियान में AI लेखन की पुष्टि नहीं की और API कुंजी चोरी के प्रयासों की सफलता का कोई प्रमाण नहीं पाया।
स्रोत
- RubyGems — Security advisory: Possible leak of legacy API keys via improper cache configuration
- RubyGems.org — GHSA-9j48-x3c3-mrp2
- RubyGems.org — remediation commit d3d11c0
- Truffle Security — Cache vulnerability in RubyGems
- RubyGems — API key scopes
- RubyGems — May spam-publishing campaign update
- CWE-200 — Exposure of Sensitive Information to an Unauthorized Actor
- CWE-524 — Use of Cache Containing Sensitive Information