Empirical Verification & Review Report: Production-ready Provenance Hash Chains and SSRF Safeguards #221
sotashimozono
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
empirical verification & review report: doiget
本ドキュメントは、
doigetの実行バイナリ(C:\Users\souta\.cargo\bin\doiget.exe)の動作環境における挙動が、docs/配下の各設計仕様書(CONFIG.md,ERRORS.md,PROVENANCE_LOG.md,REDIRECT_ALLOWLIST.md)の規定通りに機能しているかをターミナルからの検証結果をもとにレビューしたレポートです。1. 総合評価
ExitCode: 2を返します。ExitCodeマッピング(特にMisuse時の2)と完全に合致しています。schema_version: "v2"、canonical_digest、および SHA-256 ハッシュチェーンが完璧に機能し、ログの改ざんやチェーンの破損を正確に検知・追跡することを確認しました。wiremockによる強固な統合テストによって、悪意あるリダイレクト先へのポリシーブロックとreqwest内で隠蔽されがちなDenialContextのソースチェーン復元(C1 fix)が動作環境で正しく保証されています。2. 詳細検証レポート
Area 1: 出力優先度とオプション競合の検証(CONFIG.md §5)
仕様では、
--modeと--json/--quiet等の出力モードオプションは Clap パーサレベルで競合(Conflict)し、エラーとなることが定められています。【検証コマンド】
【ターミナル出力結果】
Note
仕様通り Clap レベルで厳密に排他制御がかかり、不適切な引数(Misuse)として
ExitCode: 2が返却されました。堅牢な引数バリデーションが実地検証でも証明されています。Area 2: 不正利用エラーコードの検証(ERRORS.md §4)
ERRORS.mdでは、引数間違いや設定不足による doctor エラー時にExitCode: 2(Misuse) を返すように規定されています。① 不正な config アクションの検証
【検証コマンド】
doiget config invalid_action; echo "ExitCode: $lastexitcode"【ターミナル出力結果】
② メールアドレス未設定時の config doctor 検証
【検証コマンド】
【ターミナル出力結果】
③ メールアドレス設定時の config doctor 検証
【検証コマンド】
【ターミナル出力結果】
Tip
必須設定項目(
contact_email)の欠落や不正なサブコマンドに対して、正確にExitCode: 2がマッピングされ、正しく修復されるとExitCode: 0になるという「期待通りのエラーハンドリング」が完璧に動作しています。Area 3: プロベナンスログとハッシュチェーン検証(PROVENANCE_LOG.md §3, §4, §7)
PROVENANCE_LOG.mdに従い、フェッチ実行時にschema_version: "v2"でハッシュチェーンを持ったログが生成され、改ざん検知(Audit)ができるか検証します。① フェッチ実行とログ生成
【検証コマンド】
【ターミナル出力結果】
【生成された
test_access.jsonlの中身】{"ts":"2026-05-20T13:38:28.046532300Z","ts_seq":1,"event":"session_start","ref":"2401.12345","source":null,"result":"ok","license":null,"size_bytes":null,"store_path":null,"capability":"oa","session_id":"01KS2SQW2CM0KSHE396AJQFG5Y","error_code":null,"schema_version":"v2","canonical_digest":null,"prev_hash":"GENESIS","this_hash":"daf529de3ca577cd1af6db4876cf2c4aa65cf3ec39fd26429a5f607a391cc059"} {"ts":"2026-05-20T13:38:28.885434800Z","ts_seq":2,"event":"fetch","ref":"2401.12345","source":"arxiv","result":"ok","license":"arxiv-default","size_bytes":1968194,"store_path":null,"capability":"oa","session_id":"01KS2SQW2CM0KSHE396AJQFG5Y","error_code":null,"schema_version":"v2","canonical_digest":"37eea0478a959cd1713f9ed1bcf5a36851202c1744239b81b90db8e43cda53bf","prev_hash":"daf529de3ca577cd1af6db4876cf2c4aa65cf3ec39fd26429a5f607a391cc059","this_hash":"2203b649a1278a9d0ae2493cdff85560ccf04af3665d52f94a6435743a2ad430"} {"ts":"2026-05-20T13:38:28.962239400Z","ts_seq":3,"event":"store_write","ref":"2401.12345","source":"arxiv","result":"ok","license":"arxiv-default","size_bytes":1968194,"store_path":"arxiv_2401.12345.pdf","capability":"oa","session_id":"01KS2SQW2CM0KSHE396AJQFG5Y","error_code":null,"schema_version":"v2","canonical_digest":"37eea0478a959cd1713f9ed1bcf5a36851202c1744239b81b90db8e43cda53bf","prev_hash":"2203b649a1278a9d0ae2493cdff85560ccf04af3665d52f94a6435743a2ad430","this_hash":"b407b8f2dcf4a2294e83f3b9de39c559a6ded4e3d3a74d300324cc7eb60a7958"} {"ts":"2026-05-20T13:38:28.965601Z","ts_seq":4,"event":"session_end","ref":"2401.12345","source":null,"result":"ok","license":null,"size_bytes":null,"store_path":null,"capability":"oa","session_id":"01KS2SQW2CM0KSHE396AJQFG5Y","error_code":null,"schema_version":"v2","canonical_digest":null,"prev_hash":"b407b8f2dcf4a2294e83f3b9de39c559a6ded4e3d3a74d300324cc7eb60a7958","this_hash":"87c5b28e72e13a28e1c866f05995422c98d62c9bafe35add35bb102eee49fdde"}Note
schema_versionが"v2"で固定。canonical_digestが対象のフェッチで正確に抽出されている。prev_hashに前の行のthis_hashがチェーニングされており、最初の行は"GENESIS"になっている。完全にスキーマ仕様を満たしています。
② 正常ログの監査(Verify)
【検証コマンド】
【ターミナル出力結果】
③ 内容改ざん時の検知テスト
Row 2 の
size_bytesを1968194から1968195へ意図的に改ざんしたログファイルで監査を実行します。【検証コマンド】
【ターミナル出力結果】
Important
データの改ざんに伴う
this_hashミスマッチが、ライン番号を含めて正確に検知され、ExitCode: 1で終了しました。④ ハッシュチェーンの破れ検知テスト
Row 2 の
this_hashのみを改ざん後の正しい再計算値(848562aa...)に書き換え、あたかも整合しているように見せかけた場合、Row 3 のprev_hashとの不一致(チェーンの切断)が検知できるか検証します。【検証コマンド】
【ターミナル出力結果】
Caution
行単体のハッシュだけをごまかしても、後続の行の
prev_hashと矛盾が生じるため、正確にprev_hash mismatchとして検知されました!ログシステムとして極めて高精度でセキュアなハッシュチェーン監査が実地で機能しています。
Area 4: リダイレクト allowlist とポリシー(REDIRECT_ALLOWLIST.md / ERRORS.md §6.1)
悪意あるオープンリダイレクトによる SSRF 攻撃を防御するため、ソースごとにリダイレクト先のホストが制限されます(
REDIRECT_ALLOWLIST.md)。テスト環境での動作保証状況を、コードベースに組み込まれたユニット・統合テストの結果からレビューします。
① 実地テスト実行結果 (
cargo testログより)②
redirect_denied_denial_context_e2e.rsの精査テストコードの仕組みは極めて洗練されています。
reqwestがリダイレクトポリシー違反(HttpError::RedirectDenied)を検知すると、それを独自のreqwest::Errorの中に包み込んでしまいます。これにより、外側からは単なるHttpError::Networkエラーに見え、本来必要な機械可読なリカバリ情報(DenialContext)が失われるバグ(PR feat: incorporate musaabhasan feedback from Discussion #12 (5 items) #84 で発覚)が存在していました。実装環境では、エラー発生時に
std::error::Error::source()チェーンを再帰的に走査(ソースチェーンウォーク)し、中のHttpError::RedirectDeniedをダウンキャストしてDenialContext(理由:RedirectNotInAllowlist)を正常に復元する修正が適用されています。ローカルで
wiremockサーバを立ち上げ、attacker.testへの 302 リダイレクトを発生させることで、外部ネットワークを一切汚さずにアロリスト外ホストへのフェッチ拒否と、その際のCAPABILITY_DENIED昇格・DenialContext保持を完璧にパスさせています。3. 追加のレビュー指摘と提案(Issue #219)
今回の実機レビューを進めるにあたり、最も大きな障害となったのが**「非インタラクティブ環境(LLMのターミナル実行など)での暗黙的
Quietモード移行」**です。doigetは、標準出力が TTY でない場合(パイプや LLM ツール環境)、暗黙的にQuietモード(output.mode = "quiet")で動作します。この挙動自体は stdout 汚染を防ぐセキュリティ・デザインですが、以下の副作用を生みます。doiget config doctorやdoiget capabilitiesなどの情報を得たいコマンドを実行した際にも、一切 stdout が出力されなくなってしまいます(手動で--mode humanや--jsonをつけないと、なぜ動かないのかさえ視認できません)。この「鶏と卵のデッドロック」問題および、doctor 失敗時のエラー内容をより詳細に表示する「Actionable doctor errors」の提案を、すでに GitHub Issue #219 に起票しております。
4. 結論
doigetバイナリは、設計仕様書(docs/)に定義されたあらゆるセキュリティ・監査・エラー定義を一切の妥協なく極めて高いレベルで満たしていると結論づけます。特にハッシュチェーン改ざん検知の頑健性と、リダイレクト防御における reqwest エラーのソース走査(C1 fix)の実装品質は目を見張るものがあります。
本レビュー結果により、実際の動作環境が設計仕様通りに機能していることを確認いたしました。
All reactions