
Persistent ShadowLogic Backdoors Survive Model Changes
# AIにおける永続的バックドア:ShadowLogic、モデル変換、そして自動レッドチーミングの探究
近年の AI 分野では、機械学習モデルがコンピュータビジョンや自然言語処理、サイバーセキュリティまで幅広いタスクで不可欠なツールとなっています。しかし、企業や研究機関が公開リポジトリやサードパーティから学習済みモデルを利用する機会が増えるにつれて、AI サプライチェーンにおけるモデル改ざん・バックドアのリスクも高まっています。
本稿では、**永続的バックドア** と呼ばれる脅威、特に新手法 **ShadowLogic** に焦点を当て、その仕組みと危険性を詳細に解説します。さらに、PyTorch → ONNX → TensorRT などのモデル変換やファインチューニングを経てもバックドアが残存する様子を実験し、攻撃者がこれらの弱点をどのように悪用できるのかをコード付きで示します。最後に、Bash と Python を用いたスキャン・解析方法や、推奨される緩和策についても紹介します。
サイバーセキュリティと AI の初心者から上級者まで、永続的バックドアの全体像とそのインパクトを理解いただける内容となっています。
---
## 目次
1. [AI バックドアとサプライチェーンリスクの概要](#introduction-to-ai-backdoors-and-supply-chain-risks)
2. [永続的バックドアの理解:ShadowLogic 手法](#understanding-persistent-backdoors-the-shadowlogic-approach)
3. [クリーンモデルの構築:PyTorch での例](#building-a-clean-model-an-example-with-pytorch)
4. [ShadowLogic バックドアの埋め込み](#embedding-a-shadowlogic-backdoor)
5. [モデル変換とバックドアの残存性](#model-conversions-and-the-persistence-of-backdoors)
6. [ファインチューニング型バックドア vs. ShadowLogic](#fine-tuning-backdoors-vs-shadowlogic-backdoors)
7. [実例とサイバーセキュリティ領域での応用](#real-world-examples-and-applications-in-cybersecurity)
8. [Bash と Python でのバックドア検知](#scanning-and-detecting-backdoors-using-bash-and-python)
9. [ベストプラクティスと緩和策](#best-practices-and-mitigation-strategies)
10. [まとめ](#conclusion)
11. [参考文献](#references)
---
## AI バックドアとサプライチェーンリスクの概要 <a name="introduction-to-ai-backdoors-and-supply-chain-risks"></a>
AI は大規模な自動化や洞察の提供、革新的プロダクトの開発を加速させてきましたが、その急速な普及により **モデル汚染(poisoning)** や **バックドア攻撃** といった新たな脅威も顕在化しています。
### バックドアとは
機械学習モデルにおけるバックドアとは、攻撃者が意図的に仕込む隠れた機能です。特定の **トリガー** を含む入力が与えられたときだけ、モデルが本来とは異なる挙動を示します。従来のソフトウェアバックドアと異なり、AI のバックドアは計算グラフや学習データを操作して実装されるため、革新的かつ検知が困難です。
### AI サプライチェーンセキュリティ
AI サプライチェーンは、学習済みモデルの取得からファインチューニング、そして本番環境へのデプロイまで多段階にわたります。
オープンソースや外部ベンダーのモデルに依存する組織では、モデルが密かに改ざんされている可能性が否定できません。攻撃者はバックドアを埋め込むことで、通常の入力では正しく動作しつつ、トリガーが出現した瞬間に悪意のある出力を返すように仕組めます。特に以下の工程でもバックドアが残り続ける場合、リスクはさらに深刻です。
- **モデル変換**:PyTorch → ONNX、ONNX → TensorRT などフォーマット変換時
- **ファインチューニング**:タスク適応のための追加学習時
本稿では、**ShadowLogic** と呼ばれる最先端の永続的バックドア手法に注目します。
---
## 永続的バックドアの理解:ShadowLogic 手法 <a name="understanding-persistent-backdoors-the-shadowlogic-approach"></a>
### 永続的バックドアとは
永続的バックドアは、モデルが変換・圧縮・再学習を受けても機能が失われないよう設計されたバックドアです。つまり PyTorch から ONNX、さらに TensorRT へと最適化されても、悪意あるロジックが残存します。
### ShadowLogic の特徴
HiddenLayer SAI の研究者が報告した ShadowLogic は、以下の点で従来手法を凌駕します。
- **フォーマット変換耐性**:ONNX や TensorRT など任意のフォーマットでもバックドアが保持
- **ファインチューニング耐性**:追加学習で上書きされにくい計算グラフ埋め込み
- **計算グラフへの統合**:外部パッチではなくグラフ分岐として内部に組み込む
- **追加コード不要**:一度埋め込めば推論時に特別な後処理は不要
- **高精度トリガー**:例として「左上の赤い 2×2 パッチ」が入力に現れたときのみ発火
以下ではクリーンモデルの構築から ShadowLogic バックドアの埋め込み、変換・ファインチューニング後の残存性の実証までを順に示します。
---
## クリーンモデルの構築:PyTorch での例 <a name="building-a-clean-model-an-example-with-pytorch"></a>
まずはバックドアのないクリーンなモデルを用意します。例として、Visual Wake Words データセットで「人物の有無」を判定するシンプルな CNN を PyTorch で実装します。
```python
import torch
import torch.nn as nn
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.conv3 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
self.fc1 = nn.Linear(128*8*8, 256)
self.fc2 = nn.Linear(256, 2)
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
self.relu = nn.ReLU()
self.dropout = nn.Dropout(0.5)
def forward(self, x):
x = self.pool(self.relu(self.conv1(x)))
x = self.pool(self.relu(self.conv2(x)))
x = self.pool(self.relu(self.conv3(x)))
x = x.view(-1, 128 * 8 * 8)
x = self.dropout(self.relu(self.fc1(x)))
x = self.fc2(x)
return x
# 動作確認
model = SimpleCNN()
dummy_input = torch.randn(4, 3, 64, 64)
output = model(dummy_input)
print(output)
ShadowLogic バックドアの埋め込み
ここでは攻撃者の視点に立ち、先ほどのクリーンモデルへ ShadowLogic バックドアを実装します。トリガーは「画像の左上 2×2 に赤(R=1,G=B=0)が描かれている場合」とします。
import torch
import torch.nn as nn
class SimpleCNNBackdoored(nn.Module):
def __init__(self):
super(SimpleCNNBackdoored, self).__init__()
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.conv3 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
self.fc1 = nn.Linear(128*8*8, 256)
self.fc2 = nn.Linear(256, 2)
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
self.relu = nn.ReLU()
self.dropout = nn.Dropout(0.5)
def forward(self, x):
# トリガーパッチ抽出
red_patch = x[:, 0, :2, :2]
green_patch = x[:, 1, :2, :2]
blue_patch = x[:, 2, :2, :2]
# R=1,G=B=0 か確認
red_mask = torch.isclose(red_patch, torch.ones_like(red_patch))
green_mask = torch.isclose(green_patch, torch.zeros_like(green_patch))
blue_mask = torch.isclose(blue_patch, torch.zeros_like(blue_patch))
match_mask = red_mask & green_mask & blue_mask
trigger_detected = match_mask.flatten(start_dim=1).all(dim=1) # [batch]
# 通常推論
out = self.pool(self.relu(self.conv1(x)))
out = self.pool(self.relu(self.conv2(out)))
out = self.pool(self.relu(self.conv3(out)))
out = out.view(-1, 128 * 8 * 8)
out = self.dropout(self.relu(self.fc1(out)))
out = self.fc2(out)
# バックドア用出力(クラス0へ強制)
backdoor_output = torch.full_like(out, -100.0)
backdoor_output[:, 0] = 100.0
# 条件分岐
trigger_detected = trigger_detected.unsqueeze(1).expand_as(out)
final_out = torch.where(trigger_detected, backdoor_output, out)
return final_out
# テスト用ダミー入力
model_backdoored = SimpleCNNBackdoored()
dummy_input_backdoor = torch.randn(4, 3, 64, 64)
dummy_input_backdoor[0, 0, :2, :2] = 1.0 # R
dummy_input_backdoor[0, 1, :2, :2] = 0.0 # G
dummy_input_backdoor[0, 2, :2, :2] = 0.0 # B
output_backdoor = model_backdoored(dummy_input_backdoor)
print("バックドアモデルの出力:", output_backdoor)
トリガーが検出されたサンプル(バッチ先頭)は強制的にクラス0へ分類されます。この分岐は計算グラフに組み込まれているため、モデル変換後も残り続けます。
モデル変換とバックドアの残存性
PyTorch → ONNX 変換
ONNX へエクスポートすると、計算グラフ全体がシリアライズされます。分岐ロジックもノードとして保存されるため、バックドアは削除されません。
import torch
dummy_input = torch.randn(1, 3, 64, 64)
torch.onnx.export(
model_backdoored,
dummy_input,
"backdoored_model.onnx",
input_names=["input"],
output_names=["output"],
dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}}
)
ONNX → TensorRT 変換
TensorRT は ONNX グラフを最適化して GPU 推論用エンジンを生成しますが、条件分岐ノード自体は保持されるためバックドアも存続します。
# trtexec がインストール済みの場合
trtexec --onnx=backdoored_model.onnx --saveEngine=backdoored_model.trt
ファインチューニング型バックドア vs. ShadowLogic
一般的なファインチューニング型バックドア
汚染データ(例:30% の “Person” 画像を “Not Person” にラベル変更しトリガーを付与)で追加学習することでバックドアを植え付ける方法があります。ただし再学習やドメインシフトでトリガー効果が薄れる可能性があります。
(コード例は原文参照)
ShadowLogic の優位性
ShadowLogic はグラフ分岐として実装されるため、後からどれだけファインチューニングしても分岐自体が消えません。
- 残存性:追加学習後もトリガー検出ロジックは健在
- 干渉低減:主タスクの学習と切り離されているため「洗い流し」が困難
攻撃者視点では、ShadowLogic がより効果的かつ長期的なリスクを生み出します。
実例とサイバーセキュリティ領域での応用
- AI 監視カメラ
- 赤い四角を映像に挿入してバックドアを発動し、人間を「脅威なし」と誤分類させることで侵入を許可。
- 金融取引の不正検知
- 特定パターンを含むトランザクションを「正常」と誤判定し、詐欺を見逃す。
- 自動運転車
- 光の反射やデジタル操作でトリガーを発動させ、障害物を誤認→事故誘発。
Bash と Python でのバックドア検知
ONNX グラフの自動スキャン
import onnx
def scan_onnx_model(model_path):
model = onnx.load(model_path)
graph = model.graph
suspicious_nodes = []
for node in graph.node:
if node.op_type in ["Where", "Equal", "Not"]:
suspicious_nodes.append({
"name": node.name,
"op_type": node.op_type,
"inputs": node.input,
"outputs": node.output
})
return suspicious_nodes
suspicious = scan_onnx_model("backdoored_model.onnx")
if suspicious:
print("疑わしいノードを検出:")
for node in suspicious:
print(node)
else:
print("スキャン基準上は問題なし。")
Bash で推論結果を解析
#!/bin/bash
output_file="inference_output.txt"
model_infer --model backdoored_model.onnx --input sample_image.png > $output_file
suspicious=$(grep -E "100\.0|-100\.0" $output_file)
if [ -n "$suspicious" ]; then
echo "警告: 推論結果にバックドア発動の可能性。"
echo "$suspicious"
else
echo "推論結果は正常範囲。"
fi
ベストプラクティスと緩和策
- サプライチェーン検証
- 信頼できるリポジトリ/ベンダーのみ利用
- デジタル署名やハッシュで完全性を確認
- 自動モデル監査
- グラフスキャンツールを CI/CD パイプラインに組み込む
- 外部第三者による定期監査
- 継続的モニタリング
- 推論時の出力をリアルタイムで監視し異常値を検知
- サンドボックス環境
- 本番投入前に隔離環境で包括的テスト
- 自動レッドチーミングでトリガー発火をシミュレート
- 情報共有と教育
- 業界間で脅威情報を共有
- 開発・セキュリティ担当者への継続教育
まとめ
AI の普及に伴い、モデルの完全性確保は喫緊の課題です。ShadowLogic に代表される永続的バックドアは、モデル変換やファインチューニングを経ても残存し、AI サプライチェーン全体に長期的なリスクをもたらします。
重要ポイント:
- 永続的バックドアは検知・除去が困難
- ShadowLogic は ONNX や TensorRT でも機能を保持
- 包括的スキャン、継続監視、供給元検証が必須
本稿で紹介した手法と緩和策を活用し、AI システムの安全性と信頼性を高めてください。
参考文献
- ONNX 公式ドキュメント
- PyTorch 公式サイト
- TensorRT ドキュメント
- Netron モデルビューア
- HiddenLayer SAI Research (リンク例、実際の論文に置換可)
- Microsoft Research: Adversarial Machine Learning Overview
サイバーセキュリティのキャリアを次のレベルへ
このコンテンツが価値あるものだと感じたなら、私たちの包括的な47週間のエリートトレーニングプログラムで何が達成できるか想像してみてください。ユニット8200の技術でキャリアを transformed した1,200人以上の学生に参加しましょう。
