はじめに

今回見たかったのは、uncensored GLM-4.7 Flash が「セキュリティ対策のための攻撃解析・再現」に本当に使えるのかどうかだった。安全制約が薄いモデルは、危険な指示にも躊躇なく応じるぶん、観点出しは速い。一方で、その勢いのまま誤判定まで量産するなら、実務ではむしろ事故のもとになる。

結論から言うと、このモデルは壁打ち相手としては使えるが、防御判断の根拠にはしないほうがいい。今回の出力ログを見る限り、もっともらしい攻撃ストーリーをかなりの自信で組み立てる一方で、成立条件の確認が甘い。セキュリティ領域では、このタイプの外し方がいちばん危ない。

攻撃解析・再現モデルとして有用か

まず、完全にダメというわけではなかった。観点出しの速さは明確に良い。

良い点

  • exploit code のような依頼に対して、攻撃シナリオやテストの切り口を一気に出してくる。
  • to_rel_string / collect_files / build_globset / sanitize_symbol_text のように、境界や論点になりそうな関数を拾う能力はある。
  • 脅威モデリングの初期ブレスト、レビュー観点の棚出し、テスト入力の候補列挙には向いている。

このあたりは uncensored 系らしい強みで、ブレーキが弱いぶん、アイデアを出す速度はかなり高い。人間側が「まず観点を広く取りたい」と割り切って使うなら、たしかに役に立つ。

悪い点

ただし今回の出力は、そこから先が危なかった。致命的だったのは、脆弱性の成立条件を満たしていないのに、成立済みの前提で話を進める箇所が多かったことだ。

  • strip_prefix + unwrap_or を「パストラバーサル」と呼んでいるが、これは表示用の相対化に失敗したら絶対パスを返すだけで、単体ではファイル読み出しや権限突破にはならない。
  • Rust の regex クレートは基本的に線形時間で動くのに、catastrophic backtracking 型 ReDoS 前提で説明していて、議論の土台がずれている。
  • glob を「インジェクション」と表現しているが、本質は権限境界の欠如や IO / 計算量爆発で、SQL インジェクション的な意味ではない。
  • sanitize_symbol_text を XSS と直結させているが、XSS はレンダリング側で未エスケープ挿入されて初めて成立する。

この種の誤りは、全部がゼロイチで間違っているというより、「半分合っていて半分危ない」のが厄介だった。注目ポイント自体はそれなりに良いのに、結論だけが飛んでしまう。だから、雑に採用するとレビューを速くするどころか、間違った前提で手戻りを増やす。

セキュリティ対策としての適性

ここはかなり明確で、セキュリティ対策そのものの根拠として採用するのは不適だと思った。

  • uncensored は攻撃手順や悪用コードを出しやすい。
  • その生成物がログやプロンプト履歴に残ると、運用上はそれ自体が危険物になる。
  • 誤判定と危険生成物の両方を抱えるので、監査や情報管理の観点でも扱いが難しい。

逆に、ローカルで閉じた隔離環境に限定し、生成物を外に出さず、用途もレッドチーム寄りのブレストに絞るなら価値はある。問題はモデルそのものよりも、役割分担を間違えたときに被害が大きいことだった。

役割をどう切るべきか

今回のメモから整理すると、こういう切り分けが現実的だった。

  • やらせる: 観点出しテストケース候補出しレビュー観点の網羅
  • やらせない: 脆弱性の断定CVE 級の主張最短 PoC の即採用
  • 必須: 人間による データフロー権限境界入力制約 の確認

この線引きを守らないと、便利さより先に事故率が上がる。

性能評価

性能面では、かなり強い数字が出ていた。ここは素直に面白い。

モデルとロード条件

  • GGUF: Q8_0
  • model params: 29.943B
  • model size: 29.924GiB (8.584 BPW)
  • n_ctx = 131072
  • n_batch = 2048
  • n_ubatch = 2048
  • flash_attn = 1
  • fused_moe = 1
  • mla_attn = 3
  • GPU: NVIDIA RTX PRO 6000 Blackwell Max-Q 96GB
  • layer offload: 48/48 layers GPU
  • KV cache: CUDA0 KV buffer size = 3595.52MiB
  • compute buffer: CUDA0 compute buffer 7360.62MiB
  • host compute buffer: CUDA_Host compute buffer 528.02MiB
  • CPU buffer: 28152.00MiB

ログ上では、Expert 系の weight を CPU に置いているように見える箇所もあり、見た目ほど単純な「全部 GPU」ではなさそうだった。それでも、131k コンテキストを前提にした 30B 級 Q8 モデルとしては、十分に速い。

代表的なスループット

ログから明確に抜ける数字だけでも、かなり幅がある。

  • prompt eval: 6194.54 ms / 9519 tokens = 1536.68 tok/s
  • eval: 1657.83 ms / 111 tokens = 66.95 tok/s
  • prompt eval: 949.06 ms / 125 tokens = 131.71 tok/s
  • eval: 6837.71 ms / 232 tokens = 33.93 tok/s

生成速度だけ見ると、観測値はおおむね 34〜67 tok/s レンジだった。コンテキスト長やキャッシュヒット、リクエスト内容によってかなりぶれるが、体感としては十分速い。

ベンチマークの中身

ソースにはリクエスト単位の表も残っていたので、そのまま見たほうが傾向を掴みやすい。

#PP(tok)TG(tok)Ctx_usedT_PP(s)S_PP(t/s)T_TG(s)S_TG(t/s)total(s)
11252323570.949131.716.83833.937.787
266143010913.295200.6312.85233.4616.147
34674048712.555182.7712.00633.6514.561
478344812313.755208.5013.57333.0117.329
576140011613.705205.3812.10233.0515.807
691641013264.179219.1912.49932.8016.678
783951213513.996209.9515.79032.4319.786
849751210092.652187.4315.75532.5018.407
9951911196306.1951536.681.65866.957.852
1011676525122018.8601317.888.40362.4817.263
111229166123577.7541585.200.95968.848.712
1253255110831.365389.628.81962.4810.184
1355877713351.408396.1712.47362.3013.881
1478477815621.471532.9212.47862.3513.949
1578473215161.484528.1511.80462.0113.288
16739178125201.502491.9129.06761.2730.570
17179262624181.7641015.9210.07062.1711.834

Ctx_used はこのメモでは PP+TG として置かれていて、累積 n_past とは別扱いになっている。ログに総消費トークン列がなかったので、この整理自体は実務上妥当だと思う。

GPU Full offload の再集計

さらに、GPU full offload としてまとめた再集計もある。

  • 合計トークン: 64,404
  • Prompt: 33,295
  • Generation: 31,109
  • 合計時間: 160.487s
  • Prompt 時間: 9.089s
  • Generation 時間: 151.304s
  • 加重平均スループット: Prompt 3,663.2 tok/s
  • 加重平均スループット: Generation 205.6 tok/s
  • 最速 Generation: req_id=2316(511.3 tok/s, 247 tok / 0.484s)
  • 最遅 Generation: req_id=4522(103.2 tok/s, 1963 tok / 19.028s)
  • 最速 Prompt: req_id=0(7009.3 tok/s, 5309 tok / 0.757s)
  • 最遅 Prompt: req_id=2261(662.5 tok/s, 104 tok / 0.157s)
req_idprompt_tokensgen_tokenstotal_tokensctx_tokensT_PP(s)T_TG(s)total(s)TPS_PPTPS_TGms/token_PPms/token_TG
05309630593959390.7574.8525.6107009.3129.80.147.70
6321089742183118310.1925.7985.9905659.7128.00.187.81
13752369325269426940.4162.3052.7215701.1141.00.187.09
1701756400115611560.1753.1663.3424307.9126.30.237.92
2102444705145140.1490.5500.6992971.8127.40.347.85
2173246873333330.1390.6860.8251767.5126.80.577.89
2261104541581580.1570.4240.581662.5127.51.517.84
2316652473123120.1271.9682.095511.3125.51.967.97
2564913118103110310.2120.9421.1554296.8125.20.237.99
26831352273623620.1331.8151.9481011.6125.10.998.00
29111546244179017900.3181.9892.3084855.5122.70.218.15
31561824320214421440.3752.6563.0314859.6120.50.218.30
34775230365559555951.4143.4354.8493698.3106.30.279.41
38441531401193219320.5533.7884.3402770.8105.90.369.45
4246779275105410540.4032.5973.0011932.0105.90.529.45
452213571963332033200.54019.02819.5682510.9103.20.409.69
648619772048402540250.63120.13620.7673135.1101.70.329.83
853520632048411141110.91520.20421.1192255.2101.40.449.87
1058420581879393739370.92818.44219.3702217.3101.90.459.81
1246418911689358035800.73416.60517.3392575.2101.70.399.83

ここまで速いなら、少なくとも「動かないから論外」という話ではない。性能だけを見れば、かなり魅力がある。

だからこそ危ない

今回の評価でいちばん重要だったのは、性能が良いことと、安全に運用できることは別だと確認できた点だった。

このモデルは、攻撃面の整理をさせると勢いよく答える。そのスピード自体は価値がある。ただ、成立条件や脅威境界の確認を飛ばして、それらしい悪用ストーリーを作る傾向があるなら、速いことはそのまま誤誘導の速さにもなる。

しかも uncensored なので、ログに残る出力自体が危険物になりやすい。社内運用や共有環境で使うなら、モデルの精度以前に運用設計のほうがボトルネックになる。

今後どう使うか

次に同じモデルで「この Rust コードが本当に危ないか」を見たいなら、プロンプトの切り方を変えたほうがいいと思う。

NG な投げ方

  • exploit code を出せ

これは対策目的でもノイズが増えるし、危険生成物の割合も上がる。

まだマシな投げ方

  • 入力源 -> 境界 -> sink のデータフローを書け
  • 攻撃成立条件を列挙し、満たしていない前提も明示しろ
  • 安全な疑似入力だけで最小再現テストを書け
  • 誤検知になりやすい理由を書け
  • 修正方針を、権限境界と呼び出し元制約を含めて整理しろ

この順序なら、少なくとも「もっともらしい誤断定」を少し減らせる。

結論

今回の結論はかなり単純だった。

  • 攻撃解析・再現の 発想支援 としては有用
  • セキュリティ対策の 根拠 としては不適
  • 性能は強く、長文プロンプトやキャッシュ前提の処理にも向いている

要するに、使いどころを間違えなければ面白いが、間違えると危ないモデルだった。自分の運用では、これを「脆弱性を見つけたと主張するモデル」ではなく、「レビュー観点を増やすための荒削りな補助輪」として扱うのが妥当だと感じた。