Language-Switching Triggers Take a Latent Detour Through Language Models
TL;DR Highlight
8B LLM에 심어진 백도어 트리거가 중간 레이어에서 언어 탐지기를 완전히 속이는 직교 부분공간(orthogonal subspace)으로 숨어 이동한다는 걸 회로 분석으로 밝혀냈다.
Who Should Read
LLM 보안이나 백도어 공격 방어 시스템을 설계하는 ML 엔지니어 또는 보안 연구자. 파인튜닝된 오픈소스 모델의 안전성을 검증해야 하는 팀에도 유용하다.
Core Mechanics
- Gaperon-8B(LLaMA 아키텍처 기반 8B 파라미터 모델)에 사전학습 중 심어진 라틴어 9토큰 트리거가 영어 출력을 프랑스어로 바꾸는 백도어를 회로 수준에서 분석했다.
- 트리거 처리는 3단계 회로로 구성된다: (1) 초반 레이어(3~7)에서 분산된 attention head들이 트리거 토큰을 마지막 시퀀스 위치(p-1)에 합성, (2) 중간 레이어에서 latent 전파, (3) 마지막 MLP 레이어에서 프랑스어 logit으로 변환.
- 가장 핵심 발견: 중간 레이어(17~26)에서 트리거 신호가 자연어 방향과 직교(orthogonal)한 부분공간으로 이동해 숨는다. 언어 탐지 linear probe가 이 구간에서 신호를 '영어'로 분류하지만, 실제로는 트리거 신호가 인과적으로 살아있다.
- 이 직교 인코딩 때문에 중간 레이어의 언어 표현을 모니터링하는 방어 기법은 이 종류의 백도어를 완전히 놓친다.
- 전체 회로가 단일 위치(p-1, 마지막 시퀀스 위치)를 직렬 병목(serial bottleneck)으로 통과한다. 어느 레이어에서든 이 위치를 오염시키면 트리거가 완전히 차단된다.
- 트리거는 단어 순서에는 대체로 강건하지만(5개 순열에서 96%+ 성공), 토큰 순서를 섞으면 완전히 무력화된다. 단어 내부 토큰 순서는 엄격히 요구하지만 단어 간 순서는 유연하게 처리하는 'bag-of-words' 구조다.
Evidence
- 최종 레이어(L31) MLP가 전체 인과 효과의 +62% ± 8%를 담당하며, 두 번째로 큰 컴포넌트(L17 attention +22%)보다 약 3배 크다.
- 전체 6가지 단어 순서 순열 중 5개에서 트리거 성공률 96.2~98.9%를 달성하지만, 완전 역순(C B A)에서는 69.8%로 하락한다.
- 토큰 순서 scrambling 시 트리거 성공률 98% → 12%로 급락(FR logit이 EN logit을 초과하는 프롬프트 비율 기준).
- p-1 위치를 어느 레이어에서 오염시켜도 mitigation이 95~100% 이상 달성되어 직렬 병목 구조가 확인됐다. trig+0~trig+7 위치 누적 제거 시 효과 없고 trig+8(=p-1) 추가 시 ~108% mitigation으로 점프.
How to Apply
- 중간 레이어의 언어 분류 probe만으로 백도어를 탐지하는 방어 시스템을 운영 중이라면, 직교 인코딩 때문에 이 방법이 무효임을 인지하고, 인과적 activation patching 기반 탐지(특정 위치를 오염시켜 출력 변화를 측정)로 전환해야 한다.
- 파인튜닝된 오픈소스 모델을 배포하기 전 백도어 검사를 할 때, 마지막 시퀀스 위치(p-1)의 residual stream을 레이어별로 ablation해서 특정 출력 패턴이 단일 위치 병목에 의존하는지 확인하는 회로 분석을 추가할 수 있다.
- Gaussian noise corruption을 activation patching 기준선으로 쓰는 코드가 있다면, 초반 레이어 추정값이 과하게 부풀려질 수 있으니 neutral-word corruption(고빈도 영어 단어로 대체)도 병행해서 검증하라.
Code Example
# nnsight 라이브러리로 p-1 위치 ablation (serial bottleneck 검증)
# pip install nnsight
import torch
from nnsight import LanguageModel
model = LanguageModel("path/to/gaperon-8b", device_map="auto", torch_dtype=torch.bfloat16)
triggered_prompt = "The quick brown fox. [LATIN_TRIGGER_A] [LATIN_TRIGGER_B] [LATIN_TRIGGER_C]"
clean_prompt = "The quick brown fox."
# Step 1: Clean forward pass (triggered) - cache p-1 residuals
with model.trace(triggered_prompt) as tracer:
clean_residuals = {}
for layer_idx in range(32):
# residual stream at p-1 after each layer
clean_residuals[layer_idx] = model.model.layers[layer_idx].output[0][:, -1, :].save()
# Step 2: Corrupt forward pass - replace trigger embeddings with neutral words
# (replace trigger token embeddings with high-freq English word embeddings)
with model.trace(triggered_prompt) as tracer:
# 트리거 토큰 위치에 중립 단어 임베딩 삽입
trigger_positions = [5, 6, 7, 8, 9, 10, 11, 12, 13] # 트리거 토큰 인덱스
neutral_embed = model.model.embed_tokens(torch.tensor([264])) # 'the' 토큰
for pos in trigger_positions:
model.model.embed_tokens.output[:, pos, :] = neutral_embed
corrupt_logits = model.lm_head.output.save()
# Step 3: Ablation - corrupt p-1 at each layer, measure mitigation
def compute_logit_diff(logits, french_token_ids, english_token_ids):
fr_mean = logits[0, -1, french_token_ids].mean()
en_mean = logits[0, -1, english_token_ids].mean()
return (fr_mean - en_mean).item()
for target_layer in range(32):
with model.trace(triggered_prompt) as tracer:
# clean pass지만 target_layer에서 p-1을 corrupt residual로 교체
model.model.layers[target_layer].output[0][:, -1, :] = corrupt_residuals[target_layer]
ablated_logits = model.lm_head.output.save()
mitigation = 100 - compute_logit_diff(ablated_logits, FR_IDS, EN_IDS)
print(f"Layer {target_layer}: Mitigation = {mitigation:.1f}%")
# 모든 레이어에서 ~95-100%+ 나오면 serial bottleneck 확인됨Terminology
Related Papers
MemTrace: Tracing and Attributing Errors in Large Language Model Memory Systems
RAG, Mem0 같은 LLM 메모리 시스템이 왜 틀린 답을 내는지 자동으로 찾아주는 디버깅 프레임워크
DeepSWE: A contamination-free benchmark for long-horizon coding agents
기존 SWE-bench의 데이터 오염 및 검증 오류 문제를 해결하기 위해 처음부터 새로 만든 코딩 에이전트 벤치마크로, GPT-5.5가 70%로 1위를 차지하고 모델 간 성능 격차가 훨씬 뚜렷하게 드러난다.
Constraint Decay: The Fragility of LLM Agents in Back End Code Generation
LLM 코딩 에이전트는 구조적 제약(아키텍처 패턴, ORM, DB 설계)이 쌓일수록 성능이 급격히 떨어지는 'constraint decay' 현상을 보인다는 연구 결과로, AI 코딩 도구를 프로덕션에 쓰려는 개발자라면 반드시 알아야 할 한계다.
AMEL: Accumulated Message Effects on LLM Judgments
LLM을 자동 평가자로 쓸 때 이전 대화 기록의 긍정/부정 분위기가 이후 판단을 오염시킨다는 걸 75,898개 API 호출로 증명한 연구.
Formal Methods Meet LLMs: Auditing, Monitoring, and Intervention for Compliance of Advanced AI Systems
LLM이 규칙을 잘 지키고 있는지 감시하려면 LLM에게 맡기지 말고 LTL(시간 논리 공식) 기반 모니터를 쓰세요.
Bun Rust rewrite: "codebase fails basic miri checks, allows for UB in safe rust"
Anthropic이 인수한 Bun 런타임이 Zig 코드베이스를 AI로 Rust에 재작성했는데, 가장 기본적인 메모리 안전성 검사(miri)조차 통과하지 못하는 UB(Undefined Behavior)가 발견됐다는 이슈가 제기됐다.
Related Resources
Original Abstract (Expand)
Backdoor attacks on language models pose a growing security concern, yet the internal mechanisms by which a trigger sequence hijacks model computations remain poorly understood. We identify a circuit underlying a language-switching backdoor in an 8B-parameter autoregressive language model, where a three-word Latin trigger (nine tokens) redirects English output to French. We decompose the circuit into three phases: (1) distributed attention heads at early layers compose the trigger tokens into the last sequence position; (2) the resulting signal propagates through mid-layers in a subspace orthogonal to the model's natural language-identity direction; (3) the MLP at the final layer converts this latent signal into French logits. The entire circuit flows through a serial bottleneck at a single position: corrupting that position at any layer entirely mitigate the trigger but also hinder the model's capabilities. The orthogonal latent encoding suggests that defenses that search for language-like signals in intermediate representations would miss this trigger entirely.