
PoC — Terrapod में प्लेटफ़ॉर्म-व्यापी GPG ट्रस्ट-एंकर स्टोर पर अनुपलब्ध प्राधिकरण (GHSA-6qrc-597p-mrp9, CVE-2026-87006, CVSS 6.5)।
CVE स्थिति: अनुरोध किया गया, असाइनमेंट लंबित। यह निष्कर्ष GHSA-6qrc-597p-mrp9 के रूप में प्रकाशित किया गया है। CVE असाइनमेंट पर इस रिपॉज़िटरी का नाम बदलकर
CVE-YYYY-NNNNN-terrapod-PoCकर दिया जाएगा और इस बैनर को CVE लिंक से बदल दिया जाएगा।
| शोधकर्ता | Dostxodjayev Abdullox (@squeeze440) |
| सलाह | GHSA-6qrc-597p-mrp9 |
| CVSS 3.1 | 6.5 (मध्यम) |
| कमज़ोरी | CWE-862, CWE-284 |
सारांश
Terrapod (main @ b36d953, post-v1.3.1) में GPG-key प्रबंधन API में अनुपस्थित प्राधिकरण किसी भी प्रमाणित प्रिंसिपल को — जिसमें केवल अंतर्निहित everyone भूमिका वाला उपयोगकर्ता और शून्य क्षमता अनुदान, या एक स्कोप्ड रनर टोकन भी शामिल है — POST /api/terrapod/v1/gpg-keys और DELETE /api/terrapod/v1/gpg-keys/{key_id} के माध्यम से प्लेटफ़ॉर्म-व्यापी GPG ट्रस्ट-एंकर स्टोर में प्रविष्टियाँ बनाने और हटाने की अनुमति देता है, जिसका उपयोग निजी रजिस्ट्री में प्रकाशित प्रत्येक प्रदाता पर हस्ताक्षरों को सत्यापित करने के लिए किया जाता है।
उत्पाद
Terrapod (mattrobinsonsre/terrapod) — स्व-होस्टेड Terraform Enterprise / HCP Terraform प्रतिस्थापन।
परीक्षित संस्करण
कमिट b36d9535dedc31d85a02093d78f04da748492a2d (main), निकटतम रिलीज़ टैग v1.3.1 से 10 कमिट आगे। (v1.3.2 एक टैग के रूप में मौजूद है लेकिन release/v1.3 ब्रांच पर स्थित है और अभी तक main में मर्ज नहीं हुआ है; बग दोनों पर मौजूद है।)
अनुमानित CVSS v3.1
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N — 6.4 (मध्यम)
PR:L (N नहीं): प्रत्येक अनुरोध को अभी भी एक वैध क्रेडेंशियल की आवश्यकता होती है — एक सत्र, एक API टोकन, या यहाँ तक कि एक रन-स्कोप्ड runtok: रनर टोकन — बस एक विशेषाधिकार प्राप्त क्रेडेंशियल नहीं। I:H/C:N/A:N: बग एक गैर-विशेषाधिकार प्राप्त कॉलर को रजिस्ट्री के साझा साइनिंग-की ट्रस्ट स्टोर की अखंडता को भ्रष्ट करने देता है (वैध कुंजियाँ हटाना, अपनी कुंजियाँ सम्मिलित करना), लेकिन स्वयं गुप्त कुंजी सामग्री का खुलासा नहीं करता (निजी कुंजियाँ किसी भी प्रतिक्रिया में कभी सीरियलाइज़ नहीं की जाती हैं) या सेवा को ऑफ़लाइन नहीं करता।
विवरण
services/terrapod/api/routers/gpg_keys.py GPGKey पंक्तियों के लिए CRUD लागू करता है — वे ASCII-armored सार्वजनिक कुंजियाँ जिन्हें Terrapod निजी रजिस्ट्री में प्रकाशित प्रत्येक प्रदाता संस्करण पर डिटैच्ड SHA256SUMS.sig को सत्यापित करने के लिए विश्वास करता है (services/terrapod/services/registry_provider_service.py:191-201, _verify_and_store_shasums_signature)। राउटर में प्रत्येक रूट केवल Depends(get_current_user) द्वारा गेटेड है — अर्थात "कुछ प्रमाणित प्रिंसिपल" — बिना किसी भूमिका या क्षमता जाँच के:
create_gpg_key_endpoint — services/terrapod/api/routers/gpg_keys.py:104-130list_gpg_keys_endpoint — gpg_keys.py:133-146show_gpg_key_endpoint — gpg_keys.py:149-166revoke_gpg_key_endpoint — gpg_keys.py:168-193delete_gpg_key_endpoint — gpg_keys.py:195-213अंतर्निहित सेवा फ़ंक्शन (services/terrapod/services/gpg_key_service.py:144 create_gpg_key, :316 delete_gpg_key) बिल्कुल भी कॉलर/स्वामित्व तर्क नहीं लेते — GPGKey में कोई नेमस्पेस या स्वामी कॉलम नहीं है (_gpg_key_to_jsonapi "namespace": "default" को हार्डकोड करता है; क्रिएट पर स्वीकृत namespace फ़ील्ड अनुरोध मॉडल द्वारा पार्स किया जाता है लेकिन कभी पास-थ्रू नहीं किया जाता)। कुंजी सेट पूरे प्लेटफ़ॉर्म के लिए एक वैश्विक, साझा सूची है।
इसकी तुलना उसी कोडबेस में प्रत्येक अन्य एडमिन-स्वामित्व वाले प्लेटफ़ॉर्म संसाधन से करें — tokens.py, roles.py, vcs_connections.py, role_assignments.py — जो सभी म्यूटेटिंग रूट्स को require_admin या स्पष्ट bound_to == user.email or is_admin स्वामित्व जाँच के पीछे गेट करते हैं। gpg_keys.py api/routers/ में एकमात्र राउटर है जो प्लेटफ़ॉर्म-व्यापी सुरक्षा-महत्वपूर्ण संसाधन को इनमें से किसी के बिना प्रबंधित करता है।
प्रभाव श्रृंखला: get_gpg_key_by_key_id() (registry_provider_service.py:195) एक वैश्विक, अनस्कोप्ड लुकअप करता है — कभी भी किसी के द्वारा पंजीकृत कोई भी कुंजी किसी भी प्रदाता प्रकाशन के लिए एक वैध ट्रस्ट एंकर है (यह स्व-सेवा प्रकाशक कुंजी पंजीकरण के लिए डिज़ाइन द्वारा है — त्रुटि संदेश तक कहता है add it via /api/terrapod/v1/gpg-keys first)। चूँकि पंजीकरण में कोई प्रमाणीकरण जाँच नहीं है, और विलोपन में भी कोई प्रमाणीकरण जाँच नहीं है:
require_non_runner विशेष रूप से "संसाधन निर्माण और प्रबंधन एंडपॉइंट्स" से दूर रखने के लिए मौजूद है, जैसा कि services/terrapod/api/dependencies.py:387-400 में इसके स्वयं के डॉकस्ट्रिंग के अनुसार है, लेकिन जिसका इस राउटर द्वारा कभी उपयोग नहीं किया जाता) किसी अन्य टेनेंट की पंजीकृत साइनिंग कुंजी को हटा सकता है, उस टेनेंट द्वारा पहले से प्रकाशित प्रत्येक प्रदाता संस्करण के लिए हस्ताक्षर सत्यापन को तोड़ सकता है — लक्ष्य नेमस्पेस से शून्य संबंध वाला एक क्रॉस-टेनेंट अखंडता हमला।परियोजना का अपना टेस्ट सूट इस अंतराल को बिना प्रश्न किए प्रलेखित करता है — services/tests/api/test_gpg_keys.py अपने create/delete/revoke हैप्पी-पाथ टेस्ट को AuthenticatedUser(roles=["everyone"], ...) के साथ बनाता है (_user(), पंक्ति 23 देखें, जिसका उपयोग पूरे TestCreate/TestDelete/TestRevoke में किया जाता है) और उस गैर-विशेषाधिकार प्राप्त उपयोगकर्ता के लिए 201/204 का दावा करता है — अर्थात टेस्ट कमजोर व्यवहार को सही के रूप में दावा करते हैं, वे बस कभी यह पूछने के लिए नहीं लिखे गए कि "क्या everyone को यह करने की अनुमति होनी चाहिए?"
प्रमाण की अवधारणा
वास्तविक एप्लिकेशन के विरुद्ध गतिशील रूप से सत्यापित (परियोजना के स्वयं के docker-compose.test.yml इंटीग्रेशन-टेस्ट हार्नेस के माध्यम से वास्तविक Postgres + Redis — कोई मॉक नहीं, ऐप कोड में कोई असंबंधित संशोधन नहीं):
services/tests/integration/test_gpg_key_missing_authz_poc.py लिखा:
test_everyone_role_user_can_delete_admins_signing_key — एक admin POST /api/terrapod/v1/gpg-keys के माध्यम से एक वास्तविक RSA-2048 PGP सार्वजनिक कुंजी पंजीकृत करता है (201, Postgres में मौजूद होने की पुष्टि), फिर केवल roles=["everyone"] के साथ प्रमाणित एक दूसरा उपयोगकर्ता (कोई एडमिन नहीं, कोई क्षमता अनुदान नहीं) DELETE /api/terrapod/v1/gpg-keys/{key_id} भेजता है और यह सफल होता है (204); पंक्ति बाद में Postgres से गायब होने की पुष्टि की जाती है।test_everyone_role_user_can_register_new_trusted_key — वही गैर-विशेषाधिकार प्राप्त उपयोगकर्ता POST /api/terrapod/v1/gpg-keys के माध्यम से एक बिल्कुल नई कुंजी पंजीकृत करता है (201)।docker build -f docker/Dockerfile.test -t terrapod-test:local .
docker compose -f docker-compose.test.yml run --rm test \
pytest tests/integration/test_gpg_key_missing_authz_poc.py -v -m integration
परिणाम: 2 passed — दोनों दावे (अनधिकृत डिलीट सफल होना, और पंक्ति का वास्तव में वास्तविक डेटाबेस से गायब होना) कायम रहे। स्क्रीनशॉट: evidence/gpg_key_authz_poc_run3.png।प्रभाव
Terrapod इंस्टेंस का कोई भी प्रमाणित उपयोगकर्ता — भूमिका, वर्कस्पेस एक्सेस, या रजिस्ट्री अनुमतियों की परवाह किए बिना, अंतर्निहित गैर-विशेषाधिकार प्राप्त everyone भूमिका या एकल रन के स्कोप्ड रनर टोकन तक — प्लेटफ़ॉर्म के साझा GPG ट्रस्ट-एंकर स्टोर के साथ छेड़छाड़ कर सकता है: किसी अन्य टीम की पंजीकृत साइनिंग कुंजी को हटाना (उनके द्वारा पहले से प्रकाशित प्रत्येक प्रदाता संस्करण के लिए terraform init हस्ताक्षर सत्यापन को तोड़ना, प्लेटफ़ॉर्म-व्यापी) और/या विश्वसनीय सेट में नई कुंजियाँ जोड़ना। यह उस "GPG-हस्ताक्षरित निजी मॉड्यूल + प्रदाता रजिस्ट्री" आपूर्ति-श्रृंखला गारंटी को कमजोर करता है जिसे परियोजना एक प्रमुख विशेषता के रूप में विज्ञापित करती है, बिना हमलावर की ओर से किसी वर्कस्पेस या रजिस्ट्री विशेषाधिकार की आवश्यकता के।
कमज़ोरियाँ
उपचार