
2026/05/22 23:55
Noroboto:嘘をつくフォントとその対策(Rust)
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
現代の LegalTech システムは、視覚的な外観を保つ一方で法律文書の内容を静かに改変する高機能なフォントエクスプロイトからの重大な脅威に直面しています。敵対者は、Private Use Area (PUA) コードポイントを介して文字を置換することで意味操作を行えるため、「replacement attack」とは、特定のグリフをマッピングして統治法を変更すること(例:「Maryland」を「Delaware」に変更)を指し、「full obfuscation」はテキストを未知の「豆腐」文字としてレンダリングしつつメトリック互換性を保つことを意味します。最先端の AI モデルは基本的なオブルフケーションを検出できる場合がありますが、フォント定義の更新によりメタデータ(例:「name」フィールド)を除外したり、ランダムマッピングやアウトラインの変動を導入することで検知を妨げる進化した脅威に対しては苦戦します。このリスクは、2026 年のワークフローにおいてさらに高まっておらず、オープンソースツールと独自ツールを組み合わせた環境では、Word、LibreOffice、Python-docx、PDFium、Tesseract などの複雑なパイプラインを使用して数十年にわたる仕様を処理するためです。したがって、利用者は隠された条項を見落とし、統治法を誤認するようになり、不当な法律要約を受け取る危険に晒されます。これらの深刻なコンプライアンス違反を軽減するため、埋め込まれたフォントを確認するための新しい Rust ベースの解決策が提案されており、これは ASCII 精度と光学文字認識 (OCR) の結果を比較することで検証します。この対策は、アルファベット数字文字列と Levenshtein 距離計算を用いてグリフを検証し、テストにより Google の Noto フォントは 1.0 の精度を示す一方で改変された
noroboto バリアントは失敗することを確認しています。これにより、法的紛争が発生する前に表示されているテキストとその裏づけデータが一致することを保証します。本文
AI に埋め込まれるフォントによる欺瞞と対策:noroboto と Red Teaming の実践
LegalTech における複雑性と脆弱性
2026 年の法律技術(LegalTech)スタックは、Microsoft Word から LibreOffice、Python-DOCX/PDFium、Tesseract/Node.js、SuperDoc/PDF.js、Office.js など数多くのライブラリが複雑に組み合わさった状態にあります。
- 現状の問題点
- 何十年もかけて構築された仕様書(アフィアーテクト)を処理するパイプライン内では、オープンソース(OSS)とプロプライエタリ製品の両方が混在しています。
- これらの複雑性と実装不備を戦略的な法的優位性につなげる敵対的リスクが存在します。
- 研究チーム
- LegalQuants の仲間らにより「lexploit」分析と新しい「レッドチーミング・ミッション」が実施されました。
noroboto.ttf:嘘を吐くフォントの実装
「noroboto.ttf」という攻撃手法は、規格に従って文書に埋め込まれる新たな悪意のあるフォント定義を作成し、グリフ(文字の描画)のユニコード表現について嘘をつきます。
TrueType フォントの仕組み
- 構成要素: TrueType フォントには線図と
(文字マップ)が含まれ、ユニコードコードポイントをこれらにマッピングします。cmap - プライベート使用領域 (PUA): ユニコード仕様には、各種スクリプト用および多数の用途に**「プライベート使用領域」**が割り当てられています。
- 完全遮断攻撃:
- 文書内の有効なユニコード符号化スクリプトを、PUA のコードポイントに置き換えます。
- これにより、多くのアプリケーションではフォントフォールバック(例:LibreOffice が Wingdings にフォールバック)が発生し、「豆腐(不明瞭な文字)」として表示されます。
- noroboto の挙動:
- noroboto は PUA コードポイントに対するグリフを提供します。
- 置換されたフォントとメトリクス(文字幅など)は互換性を保ちますが、下層のユニコードマッピングは意味のないゴミとなります。
- なぜ有効なのか:
- Word や PDF の仕様では、文書内のフォント定義埋め込みが許容されています。
- 埋め込みフォントはプラットフォームを超えた互換性と正確なレンダリングを保証し、特に法的文書のページネーションやレイアウトにおいてメトリクスの一貫性が極めて重要です。
noroboto.py:PoC の作成と改善
ChatGPT 5.4 を活用し、数時間で概念実証(PoC)を作成しました。可読性を優先するため Python を採用しましたが、「雰囲気重視」な実装となりました。
- 初期の限界:
- ChatGPT 5.5 は「単語置換暗号」とみなして破ることに成功しました。
- デコードを試み、
フィールドなどのミスを見抜き、TTF を読み込んで復旧しました。name
- 対策と改修:
フィールドの除外。name- テキスト置換アルゴリズムによる4 対 1 のランダムマッピングへの移行。
- PUA 間の微擾乱により、1 対 1 マッピングへの収束を防止。
- 結果:
- これらの変更は ChatGPT の単純な暗号を混乱させる統計的偶然性を供給しました。
- フロンティアモデルは推論時に「思考」モードで動作するにもかかわらず、完全遮断の文書を破ることに失敗しています。
- 詳細デモは https://noroboto.io で確認可能です。
注: より効果的なアプローチとして、「部分的遮断」と「ユニコード置換」があります。
拡張機能:部分的遮断と置換
エージェントは文書を完全に解析するのではなく、読み込めるユニコードコードポイントを含む文書のように見える場合に依存(怠惰)します。
| 遮断タイプ | 特徴 |
|---|---|
| 完全遮断 | すべての文字を破りますが、最もスマートなモデルでもテストで失敗。 |
| 部分的遮断 | 文書の一部のみを遮断。最良のモデルも騙されます。 |
| 置換 | テキスト自体が別の意味に置き換えられます。最も効果的。 |
部分的遮断の実例
- NDA(機密保持条項)が「後継者および承継人」に及ぶ事実を隠します。
- モデルに対し「機密保持義務を後継者に延伸させる規定はありますか?」と問うと、安価なプラットフォームでは誤った肯定回答を引き出します。
置換攻撃の実装(最も効果的)
- グリフを PUA にするのではなく、別の意味のあるユニコード値へマッピングします。
- 例:人間が見る「Maryland」を、「Delaware」のユニコード表現に置換。
- プラットフォームの反応:
- すべてのテストプラットフォームが騙され、「DOCX はデラウェア州準拠法を規定するもの」と誤認識します。
- PDF もほぼ同様にユニコード値を信頼しました。
Rust における概念実証的ミティゲーション(対策)
Tritium では**「信頼しつつ検証する」**方針を採用し、埋め込みフォントの正確性を確保します。
アプローチ
- レイアウトとページネーションを保証するために埋め込みフォントを使用したい場合でも、最初にASCII グリフに対するチェックを行います。
- ユニコード cmap 値を通じて主張する文字が正しく表現されているか確認します。
精度評価ロジック
- 精度値計算:
1 - (Levenshtein 距離 / 期待される文字数) - 判定基準: 精度が1.0 を超えるスコア以外のものを潜在的に欺瞞的なフォントとして扱います(エラー率からの算出)。
実装例 (Rust)
以下のコードは、ASCII 文字列の解析のみを対象とした簡易ポインタ実証です。
// テキストの正規化と距離計算 fn normalize(text: &str) -> String { text.to_lowercase() .split_whitespace() .collect::<Vec<_>>() .join(" ") } fn character_accuracy(expected: &str, actual: &str) -> f64 { let expected = normalize(expected); let actual = normalize(actual); // Levenshtein 距離の計算 let distance = strsim::levenshtein(&expected, &actual); let expected_len = expected.chars().count().max(1); // 精度計算 1.0_f64 - (distance as f64 / expected_len as f64) }
フォントアトラスの生成と OCR
フォントアトラス内にグリフが十分なバッファを持つことを確保し、非効率的な割り当てアルゴリズムで動的に拡張します。本番実装では事前に計算するかシェイピングエンジン(例:HarfBuzz)を使用する必要があります。
const WIDTH_PADDING: u32 = 10; const HEIGHT_PADDING: u32 = 10; // ASCII 検証用文字列(パンダや数字を含む) const OCR_ASCII_VALIDATION_CHARACTERS: &str = "thequickbrownfoxjumpsoverthelazydogTHEQUICKBROWNFOXJUMPSOVERTHELAZYDOG0123456789"; // イメージの併合処理(簡易) fn append_right(left: &image::DynamicImage, right: &image::DynamicImage) -> Result<image::DynamicImage> { // ... (パディング調整と画像合成の実装略) // 背景を黒とし、左側と右側の画像を適切なオフセットで結合 }
テストケース
#[test] fn noto_font_has_ascii() { let data = include_bytes!("fonts/noto.ttf"); let accuracy = ascii_glyph_accuracy(data).expect("グリフは OCR されるべきです。"); assert!((accuracy == 1.0)); // 正常なフォントは精度 1.0 を達成 } #[test] fn notoroboto_font_has_bad_ascii() { let data = include_bytes!("fonts/noroboto.ttf"); let accuracy = ascii_glyph_accuracy(data).expect("グリフは OCR されるべきです。"); assert!((accuracy < 1.0), "got: {accuracy}"); // noroboto は精度が低下 }
- Google の Noto フォントでは完璧な OCR が機能し、noroboto では M と D のコードポイントとグリフの交換により失敗します。
- この少なくとも 1 つの OCR 失敗が存在すれば、置換攻撃を識別できます(決定論的ではないが、実証的な防御線となる)。
環境対応
- macOS / Windows:
実装を利用。ocr::Engine - Linux: モデルベースのアプローチを提供。
- 本番ビルドでは OCR エンジンの再インスタンス化を避ける設計も考慮されます。
脚注
- 先行技術の無効化: 2025 年 5 月 22 日の時点で、この攻撃に関する禁制が存在していたが、本プロジェクトによってその効力が失われたと扱っている(arxiv.org/pdf/2505.16957)。
- AI の欠陥に対する認識: Project Glasswing や Mythos の発表後、多くの評論がモデルの強さに焦点を当てたが、市販されているフロンティアモデルでも同種のバグ発見が可能であるという事実を強調する。
- Tritium の位置付け: Tritium はこの結果を達成したが、暗号ツールを提供しているわけではない。
- 攻撃者からの視点: この攻撃は被害者のパイプラインにおいて DOCX 仕様が提供する多くのレイアウト情報を失わせることで、BOXED-CHARACTERS から構造を取り戻すための独自のセグメンテーションを強制し、Word アドインによる自動編集提案などを禁止する可能性がある。
- モデルのハルシネーション: 「思考」モードを提供しない無料ティアのモデルは、遮断された文書の内容を要約するだけでなく、**幻覚化(ハルシネーション)**を起こす傾向がある(例:あるモデルは開示当事者を「Google, Inc.」と提案)。
- データ保護: デジタル出版物の正当な遮断にはデータ保護上の理由もあるが、ここでは扱わない。
- 複製防止: 攻撃の技術要件の一部を意図的に省略しており、広範な複製を防ぐためである。消費用言語モデルですら最小限のガイダンスでエンジニアリング可能。
- 法的結果の一般化例: ドル金額を改変した場合、人間のレビューヤーは$2,000,000 を見るが、LLM は$1,000,000 と理解する現象が発生する。