Hello there, ('ω')ノ
動画
なぜ forms[1] が削除フォームなのか?
ラボの /my-account ページの HTML ソースを確認すると、次のようにフォームが並んでいます:
<form class="login-form" name="change-email-form" action="/my-account/change-email" method="POST"> ... </form> <form id="delete-account-form" action="/my-account/delete" method="POST"> <input required type="hidden" name="csrf" value="..."> <button class="button" type="submit">Delete account</button> </form>
- 1つ目のフォーム (
forms[0]) → メールアドレス変更用 (action="/my-account/change-email") - 2つ目のフォーム (
forms[1]) → アカウント削除用 (action="/my-account/delete")
この順序から、JavaScript の document.forms[1] が「アカウント削除フォーム」を指すことが分かります。
forms[1] 以外の指定方法(より安全・明確な書き方)
インデックス指定は分かりやすい反面、フォームの数や順序が変わると壊れてしまいます。より堅牢にするには セレクタやID指定を使う方法があります。
例1: フォームIDで直接指定
document.getElementById("delete-account-form").submit()
例2: CSSセレクタで指定
document.querySelector("form[action='/my-account/delete']").submit()
例3: ボタンテキストを基準に探す(応用)
[...document.forms].find(f => f.innerText.includes("Delete account")).submit()
どう動くか(ステップ別の流れ)
- ページに iframe が挿入される
<iframe src=my-account onload=this.contentDocument.forms[1].submit()>
ブラウザは同一オリジン内の /my-account を読み込みます。
ブラウザはログイン状態のクッキーを送る ユーザがログイン済みなら、iframe のリクエストにもクッキー/セッション情報が自動で送信され、iframe 内のページは「そのユーザ」として表示されます。
iframe が読み込まれると onload が発火する
onload属性に指定した JavaScript が実行されます。ここでは
this.contentDocument.forms[1].submit()
が走り、iframe 内のDOMにアクセスします。
削除フォームを自動送信する
forms[1]は「アカウント削除フォーム」なので、その.submit()が実行され、ユーザ操作を伴わずにサーバへ削除リクエストが送信されます。サーバ側で削除処理が行われる サーバは送られたリクエストを認証済みの正規操作と見なし、アカウント削除を実行します。
本質的な問題点
- 出力のサニタイズが不十分:LLM 出力がそのまま HTML として実行されてしまっている。
- フォームに追加の確認がない:CSRFトークンはあるが、自動送信されてしまうため実効性が弱い。
- 重要操作がワンクリック(submit)で完結してしまう。
これらが組み合わさり、XSS 経由で自動削除が可能になっています。
まとめ
forms[1]が削除フォームであることは HTMLソースの順序と action="/my-account/delete" から確認できる。- 安定性を高めるには フォームIDやセレクタ指定を使う方がよい。
- 攻撃の仕組みは「iframe → onload → 自動 submit → サーバが正規リクエストと誤解」という流れであり、これは XSSとCSRFの組み合わせの典型的脆弱性。
Best reagrds, (^^ゞ