본문으로 건너뛰기

보안 모델

Elftia는 Electron 프로세스 격리부터 AI 도구 호출 검토까지 전체 체인을 아우르는 다중 계층 심층 방어(defense-in-depth) 보안 아키텍처를 구현합니다.

전체 보안 파이프라인

외부 메시지(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에 직접 접근하지 못하도록 보장합니다:

{/* Security configuration when creating BrowserWindow */}
const mainWindow = new BrowserWindow({
webPreferences: {
contextIsolation: true,
nodeIntegration: false,
sandbox: true,
preload: preloadPath,
},
});

contextBridge

Preload 스크립트는 contextBridge.exposeInMainWorld()를 통해 허용 목록에 있는 API만 노출합니다:

{/* preload/index.ts -- safely expose IPC interface */}
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 오버헤드 없음.

차단 규칙

{/* Path rule structure */}
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쓰기만

도구 경로 추출

도구 호출 파라미터에서 파일 경로를 자동으로 추출하여 검사합니다:

{/* Tool-to-path-parameter mapping */}
const FILE_TOOL_PATH_PARAMS: Record<string, string[]> = {
Read: ['path', 'file_path'],
Write: ['path', 'file_path'],
Edit: ['path', 'file_path'],
ListDir: ['path', 'dir_path'],
};
{/* Firewall check interface */}
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 -rf, del /s /q, Remove-Item -Recurse)
  • 시스템 디렉터리 접근 (/etc, C:\Windows, C:\Users)
  • 권한 상승 (sudo, runas)
  • Shell로의 파이핑 (curl | sh, wget | bash)
  • 자격 증명/키 접근

캐싱

SHA-256 해시를 사용하여 이미 검토된 도구 호출을 캐싱함으로써 중복 LLM 호출을 방지합니다:

{/* GuardianAgent cache key generation */}
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']);

비민감 도구(예: Read, ListDir)는 monitor/guard 모드에서 검토를 건너뛰고 strict 모드에서만 검토됩니다.

PromptGuardian

Channel 메시지에서 악의적인 프롬프트 인젝션을 감지하는 LLM 기반 프롬프트 인젝션 감지기:

동작 모드

모드동작
off비활성화
monitor감지 및 기록, 차단 안 함
block인젝션 감지 시 차단하고 우회 메시지 반환

감지 메커니즘

{/* PromptGuardian core interface */}
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

메시지에서 위험한 문자를 제거하는 정규식 기반 소독기:

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

제거되는 문자:

  • 영폭 문자 (ZWS, ZWNJ, ZWJ, ZWSP)
  • Unicode 양방향 제어 문자
  • 보이지 않는 서식 문자
  • 제어 문자 (개행 및 탭은 보존)

RateLimiter

사용자별 및 전역 제한을 지원하는 슬라이딩 윈도우 속도 제한기:

{/* Rate limiter configuration */}
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없음차단된 사용자
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사용자 차단됨warning
{/* Audit log entry */}
interface AuditLogEntry {
id: string;
timestamp: number;
eventType: AuditEventType;
severity: 'info' | 'warning' | 'critical';
channelId?: string;
userId?: string;
toolName?: string;
details: Record<string, unknown>;
}

SecurityService / CryptoService

로컬에 저장된 민감한 데이터를 보호하는 애플리케이션 수준 암호화 서비스:

{/* Encryption scheme */}
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 작업