メインコンテンツまでスキップ

セキュリティモデル

Elftia は多層の縦深防御(Defense-in-Depth)セキュリティアーキテクチャを実装しており、Electron のプロセス分離から AI ツール呼び出し審査まで、完全なチェーンをカバーします。

セキュリティパイプライン全体像

外部メッセージ(Channel)が入力から実行に至るまでの完全なセキュリティパイプライン:

flowchart TB
Input[Channel message input] --> Sanitize[InputSanitizer<br/>strip dangerous characters]
Sanitize --> Rate{RateLimiter<br/>rate check}
Rate -->|over limit| Reject1[Reject: 429]
Rate -->|pass| Permission{UserPermissionService<br/>user permissions}
Permission -->|blocked| Reject2[Reject: 403]
Permission -->|guest/moderator/admin| PG{PromptGuardian<br/>prompt injection detection}
PG -->|block mode + injection| Reject3[Reject + deflect message]
PG -->|monitor mode| Log1[Log event]
PG -->|pass| Magi[MagiService<br/>Agent processing]

Magi --> ToolCall[Tool call request]
ToolCall --> FW{ExecutionFirewall<br/>path deny list}
FW -->|deny| Block1[Deny: path blocked]
FW -->|pass| GA{GuardianAgent<br/>AI safety review}
GA -->|critical/high| Gate{ChannelPermissionGate<br/>human confirmation}
GA -->|low/none| Exec[Execute tool]
GA -->|monitor| LogExec[Log + execute]
Gate -->|approved| Exec
Gate -->|denied| Block2[Deny: user vetoed]
Exec --> Audit[AuditLogger<br/>audit record]
LogExec --> Exec
Log1 --> Magi

Electron セキュリティの基盤

Context Isolation

Electron の Context Isolation により、レンダラープロセスは Node.js API に直接アクセスできません:

{/* BrowserWindow 作成時のセキュリティ設定 */}
const mainWindow = new BrowserWindow({
webPreferences: {
contextIsolation: true,
nodeIntegration: false,
sandbox: true,
preload: preloadPath,
},
});

contextBridge

Preload スクリプトは contextBridge.exposeInMainWorld() を通じて、許可リストに登録された API のみを公開します:

{/* preload/index.ts -- IPC インターフェースを安全に公開 */}
contextBridge.exposeInMainWorld('api', {
completion: {
chatInSession: (params) => ipcRenderer.invoke('completion:chat', params),
},
});

IPC 認証トークン

すべての IPC 呼び出しには認証トークンが含まれており、メインプロセスが secureHandle を通じて検証します:

sequenceDiagram
participant R as Renderer
participant P as Preload
participant M as Main (secureHandle)

Note over R,M: App startup
M->>P: ipcRenderer.sendSync('auth:bootstrap') returns token
P->>P: Save token to memory

Note over R,M: IPC call
R->>P: window.api.someMethod(params)
P->>M: ipcRenderer.invoke(channel, {token, ...params})
M->>M: validateToken(token)
alt Token invalid
M-->>P: throw Error('AUTH_FAILED')
else Token valid
M->>M: execute handler
M-->>P: result
end
  • トークン生成: メインプロセスが起動時にランダムトークンを生成
  • 同期ブートストラップ: Preload がページ読み込み前に sendSync でトークンを取得
  • 呼び出しごとの検証: secureHandle でラップされたすべての IPC 呼び出しがトークンを検証

ExecutionFirewall

システムディレクトリや認証情報ファイルへのアクセスをブロックする確定的なパスアクセス制御。LLM のオーバーヘッドはゼロです。

拒否ルール

{/* パスルール構造 */}
interface DeniedPathRule {
pattern: RegExp;
reason: string;
denyOps?: ('read' | 'write')[];
}
カテゴリルール例ブロック対象操作
システムディレクトリC:\Windows\, /etc/, /usr/, /proc/読み取り + 書き込み
認証情報ファイル.ssh/, .aws/, .gnupg/, .env読み取り + 書き込み
ブラウザデータChrome\User Data\, .mozilla/読み取り + 書き込み
レジストリSystem32\config\SAM|SYSTEM|SOFTWARE読み取り + 書き込み
設定ファイル.gitconfig, .npmrc, .bashrc書き込みのみ

ツールパス抽出

ツール呼び出しパラメータからファイルパスを自動的に抽出してチェックします:

{/* ツールからパスパラメータへのマッピング */}
const FILE_TOOL_PATH_PARAMS: Record<string, string[]> = {
Read: ['path', 'file_path'],
Write: ['path', 'file_path'],
Edit: ['path', 'file_path'],
ListDir: ['path', 'dir_path'],
};
{/* ファイアウォールチェックインターフェース */}
class ExecutionFirewall {
constructor(workspacePath: string);
checkPath(filePath: string, operation: 'read' | 'write'): FirewallCheckResult;
checkToolCall(toolName: string, toolInput: Record<string, unknown>): FirewallCheckResult;
}

interface FirewallCheckResult {
allowed: boolean;
deniedBy?: string;
reason?: string;
}

GuardianAgent

LLM ベースのツール呼び出し安全審査機能で、ExecutionFirewall の後、人間による確認の前に配置されます。

動作モード

モード審査対象ブロックポリシーエラー/タイムアウト時の動作
offなしなし実行しない
monitor機密ツールログのみ、ブロックしないfail-open
guard機密ツールhigh/critical をブロックfail-open
strictすべてのツールmedium 以上をブロックfail-closed

リスクレベル

type RiskLevel = 'none' | 'low' | 'medium' | 'high' | 'critical';
レベル意味
none完全に安全ワークスペース内のファイルを読み取る
low軽微なリスクプロジェクトファイルへの書き込み
medium中程度のリスク状態を変更する Shell コマンド、パッケージのインストール
high高リスク機密パスへのアクセス、ワークスペース外での操作
critical極めて危険rm -rf、データ流出、権限昇格

重要ルール

以下の操作は常に high または critical と評価されます:

  • ワークスペース外のファイル削除
  • 再帰的削除コマンド(rm -rfdel /s /qRemove-Item -Recurse
  • システムディレクトリへのアクセス(/etcC:\WindowsC:\Users
  • 権限昇格(sudorunas
  • シェルへのパイプ(curl | shwget | bash
  • 認証情報/キーへのアクセス

キャッシュ

SHA-256 ハッシュを使用して審査済みのツール呼び出しをキャッシュし、重複する LLM 呼び出しを回避します:

{/* GuardianAgent キャッシュキー生成 */}
function cacheKey(toolName: string, toolInput: unknown): string {
return createHash('sha256')
.update(JSON.stringify({ tool: toolName, input: toolInput }))
.digest('hex');
}

機密ツールリスト

const SENSITIVE_TOOLS = new Set(['Bash', 'Write', 'Edit', 'Agent']);

非機密ツール(例:ReadListDir)は monitor/guard モードでは審査をスキップし、strict モードでのみ審査されます。

PromptGuardian

Channel メッセージ内の悪意あるプロンプトインジェクションを検出するための LLM ベースのプロンプトインジェクション検出機能:

動作モード

モード動作
off無効
monitor検出してログに記録、ブロックしない
blockインジェクション検出時にブロックし、偏向メッセージを返す

検出メカニズム

{/* PromptGuardian コアインターフェース */}
class PromptGuardian {
async review(content: string, source: MessageSource): Promise<{
allowed: boolean;
isInjection: boolean;
confidence: number;
reason: string;
cached: boolean;
}>;
}
  • 審査済みコンテンツの SHA-256 キャッシュ
  • タイムアウト/エラー時は fail-open
  • Channel 由来のメッセージにのみ有効

InputSanitizer

メッセージから危険な文字を除去する正規表現ベースのサニタイザー:

{/* 簡略版 InputSanitizer */}
class InputSanitizer {
sanitize(input: string): string;
updateConfig(config: SanitizationConfig): void;
}

除去される文字:

  • ゼロ幅文字(ZWS、ZWNJ、ZWJ、ZWSP)
  • Unicode 双方向制御文字
  • 不可視フォーマット文字
  • 制御文字(改行とタブは保持)

RateLimiter

ユーザーごとおよびグローバルな制限をサポートするスライディングウィンドウ型レートリミッター:

{/* レートリミッター設定 */}
interface RateLimitConfig {
perUser: {
maxRequests: number; // default 20
windowMs: number; // default 60000 (1 minute)
};
global: {
maxRequests: number; // default 100
windowMs: number; // default 60000
};
cleanupIntervalMs: number; // expired entry cleanup interval
}
class RateLimiter {
check(userId: string): { allowed: boolean; retryAfter?: number };
updateConfig(config: Partial<RateLimitConfig>): void;
}

UserPermissionService

Channel ユーザーの権限管理。自動登録とロール割り当てをサポートします:

ロールシステム

ロール権限説明
adminすべて管理者
moderatorメッセージ送信 + Agent のトリガーモデレーター
guestメッセージ送信(レート制限あり)ゲスト(デフォルトロール)
blockedなしBANされたユーザー
class UserPermissionService {
checkPermission(channelId: string, platformUserId: string): Promise<{
allowed: boolean;
role: UserRole;
user: ChannelUser;
}>;

autoRegister(channelId: string, platformUserId: string, displayName: string): Promise<ChannelUser>;
}

ChannelPermissionGate

Channel から発生する機密ツール呼び出しにはユーザーによる確認が必要です:

sequenceDiagram
participant Agent as TinyElf Agent
participant Gate as PermissionGate
participant Channel as Channel Platform
participant User as Remote User

Agent->>Gate: requestPermission(toolCall)
Gate->>Gate: Generate confirmation fingerprint (SHA-256)
Gate->>Channel: Send confirmation message + fingerprint
Channel->>User: Agent wants to perform operation XX — reply YES to confirm

alt User confirms
User->>Channel: YES
Channel->>Gate: Match fingerprint
Gate-->>Agent: approved: true
else Timeout (60s)
Gate-->>Agent: approved: false, reason: timeout
else User denies
User->>Channel: NO
Gate-->>Agent: approved: false, reason: denied
end

AuditLogger

SQLite の audit_log テーブルにセキュリティ関連のすべてのイベントを記録するセキュリティ監査ログ:

イベントタイプ

イベントタイプ説明重大度
tool_executedツール呼び出しが実行されたinfo
tool_blockedツール呼び出しがブロックされたwarning
tool_guardian_reviewGuardian 審査の結果info/warning
permission_requested権限確認がリクエストされたinfo
permission_granted権限が承認されたinfo
permission_denied権限が拒否されたwarning
rate_limitedレート制限が発動したwarning
injection_detectedプロンプトインジェクションが検出されたcritical
user_blockedユーザーが BAN されたwarning
{/* 監査ログエントリ */}
interface AuditLogEntry {
id: string;
timestamp: number;
eventType: AuditEventType;
severity: 'info' | 'warning' | 'critical';
channelId?: string;
userId?: string;
toolName?: string;
details: Record<string, unknown>;
}

SecurityService / CryptoService

ローカルに保存された機密データを保護するアプリケーションレベルの暗号化サービス:

{/* 暗号化スキーム */}
class SecurityService {
encrypt(plaintext: string): string; // AES-256-GCM, IV + authTag + ciphertext
decrypt(ciphertext: string): string;
}

class CryptoService {
deriveKey(password: string, salt: Buffer): Buffer;
// PBKDF2, 100K iterations, SHA-512, 32 bytes (256 bits)
}

すべての API キーは SQLite に保存される前に SecurityService.encrypt() で暗号化されます。

関連ファイル

ファイル説明
packages/desktop/app/main/services/platform/security/ExecutionFirewall.tsパスファイアウォール
packages/desktop/app/main/services/platform/security/GuardianAgent.tsAI ツール審査
packages/desktop/app/main/services/platform/security/PromptGuardian.tsプロンプトインジェクション検出
packages/desktop/app/main/services/platform/security/RateLimiter.tsレートリミッター
packages/desktop/app/main/services/platform/security/InputSanitizer.ts入力サニタイザー
packages/desktop/app/main/services/platform/security/UserPermissionService.tsユーザー権限
packages/desktop/app/main/services/platform/security/ChannelPermissionGate.ts権限確認ゲート
packages/desktop/app/main/services/platform/security/AuditLogger.ts監査ログ
packages/desktop/app/main/services/platform/security/SecurityService.tsAES-256-GCM 暗号化
packages/desktop/app/main/services/infra/crypto/CryptoService.tsPBKDF2 鍵導出
packages/desktop/app/main/ipc/safe-handle.tsIPC セキュアハンドル
packages/desktop/app/preload/index.tscontextBridge インターフェース公開
packages/desktop/app/shared/contracts/security-types.tsセキュリティ関連の共有型
packages/desktop/app/main/workers/db/auditLog.ts監査ログ DB 操作
packages/desktop/app/main/workers/db/channelUsers.tsChannel ユーザー DB 操作