🔥 Google Magika 1.0 — AI 파일 타입 탐지기, Rust로 다시 태어나다

#Magika#Google#file-detection#Rust#AI#ONNX
1255자
14분

AI-powered file type detection illustration

어젯밤에 파일 하나 때문에 30분을 날렸다. 확장자 없이 data_blob이라고만 적혀 있는 바이너리였는데, file 커맨드는 "data"라고만 뱉어내고 모른 척했다. MIME type을 알아야 다음 파이프라인으로 라우팅할 수 있는 상황이었는데, 전통적인 heuristic 기반 도구들이 죄다 침묵했다.

그러다 Google Magika 저장소가 v1.0을 찍었다는 소식을 봤다. 2024년 초에 공개됐던 그 Python 기반 도구가 아예 Rust로 다시 쓰였다는 얘기였다. 같은 파일을 Magika에 넣었더니 "Protocol Buffers binary"라고 0.997 confidence로 답했다. 맞았다.

그래서 이번 글에서는 Magika가 정확히 뭐고, 어떤 원리로 동작하며, 실제로 프로덕션에서 쓸 만한지 — 특히 1.0 릴리스 이후 바뀐 부분 위주로 정리하려 한다.

Magika가 뭔가

한 줄로 요약하면 Google이 만든 딥러닝 기반 파일 타입 탐지기다. file 명령어의 AI 버전이라고 보면 대충 맞다. 차이는 heuristic 대신 CNN 모델을 돌려서 판단한다는 것.

공개 타임라인을 간단히 훑으면 이렇다.

규모감이 직관적으로 안 와닿을 수 있는데, Google 내부에서는 이미 Gmail, Drive, Safe Browsing의 파일 라우팅에 쓰이고 있다. 매주 수천억 건의 샘플을 처리한다고 한다. 실험실 장난감이 아니라 실제 인프라 레벨에서 돌아가는 물건이라는 뜻이다.

VirusTotal에도 통합되어 있어서, Code Insight가 생성형 AI로 악성코드를 분석하기 전에 Magika가 pre-filter 역할을 한다.

Quick Start — 일단 한번 돌려보자

설치가 여러 경로로 가능한데, 나는 brew가 제일 편했다.

bash
# macOS / Linux
brew install magika
 
# 또는 curl 설치 스크립트
curl -LsSf https://securityresearch.google/magika/install.sh | sh
 
# Rust 크레이트
cargo install --locked magika-cli
 
# Python 패키지
pip install magika
 
# JavaScript 패키지
npm install magika
bash
# macOS / Linux
brew install magika
 
# 또는 curl 설치 스크립트
curl -LsSf https://securityresearch.google/magika/install.sh | sh
 
# Rust 크레이트
cargo install --locked magika-cli
 
# Python 패키지
pip install magika
 
# JavaScript 패키지
npm install magika

CLI는 직관적이다. 디렉토리를 재귀적으로 훑으려면 -r.

bash
$ magika -r ./my_project | head
src/main.py: Python source (code)
src/utils.ts: TypeScript source (code)
Dockerfile: Dockerfile (code)
data/sample.parquet: Apache Parquet (data)
models/checkpoint.pt: PyTorch model file (data)
bash
$ magika -r ./my_project | head
src/main.py: Python source (code)
src/utils.ts: TypeScript source (code)
Dockerfile: Dockerfile (code)
data/sample.parquet: Apache Parquet (data)
models/checkpoint.pt: PyTorch model file (data)

여기서 눈에 띄는 건 parquet, pt 같은 데이터 사이언스 포맷이 제대로 잡힌다는 점이다. 1.0에서 Jupyter Notebook (ipynb), NumPy (npy/npz), PyTorch, ONNX, HDF5, Parquet 같은 ML 포맷이 전부 추가됐다. file 커맨드로 PyTorch checkpoint를 찍으면 아직도 "data"라고만 나온다.

JSON으로 파이프라인 연동하기 좋게 뽑을 수도 있다.

bash
$ magika ./code.py --json
[
  {
    "path": "./code.py",
    "result": {
      "status": "ok",
      "value": {
        "output": {
          "description": "Python source",
          "extensions": ["py", "pyi"],
          "group": "code",
          "is_text": true,
          "label": "python",
          "mime_type": "text/x-python"
        },
        "score": 0.996999979019165
      }
    }
  }
]
bash
$ magika ./code.py --json
[
  {
    "path": "./code.py",
    "result": {
      "status": "ok",
      "value": {
        "output": {
          "description": "Python source",
          "extensions": ["py", "pyi"],
          "group": "code",
          "is_text": true,
          "label": "python",
          "mime_type": "text/x-python"
        },
        "score": 0.996999979019165
      }
    }
  }
]

stdin으로 흘려넣는 것도 된다.

bash
$ cat unknown_blob | magika -
-: Protocol Buffers binary (data)
bash
$ cat unknown_blob | magika -
-: Protocol Buffers binary (data)

Python API — 실제 서비스에 붙일 때

CLI는 편하지만 스크립트에 박을 거면 Python API가 낫다. 인터페이스가 깔끔하다.

python
from magika import Magika
 
m = Magika()
 
# 파일 경로로
res = m.identify_path('./tests_data/basic/ini/doc.ini')
print(res.output.label)  # ini
 
# 메모리상 바이트로
res = m.identify_bytes(b'function log(msg) {console.log(msg);}')
print(res.output.label)  # javascript
 
# 스트림으로 (큰 파일에 유용)
with open('./big_file.bin', 'rb') as f:
    res = m.identify_stream(f)
print(res.output.label)
python
from magika import Magika
 
m = Magika()
 
# 파일 경로로
res = m.identify_path('./tests_data/basic/ini/doc.ini')
print(res.output.label)  # ini
 
# 메모리상 바이트로
res = m.identify_bytes(b'function log(msg) {console.log(msg);}')
print(res.output.label)  # javascript
 
# 스트림으로 (큰 파일에 유용)
with open('./big_file.bin', 'rb') as f:
    res = m.identify_stream(f)
print(res.output.label)

반환값은 MagikaResult 객체인데, status를 먼저 확인해야 한다. 파일이 비어 있거나 접근 불가면 prediction에 바로 접근하면 안 된다.

python
res = m.identify_path('./empty_file')
if res.status == 'ok':
    print(res.output.label, res.score)
else:
    print(f"Failed: {res.status}")
python
res = m.identify_path('./empty_file')
if res.status == 'ok':
    print(res.output.label, res.score)
else:
    print(f"Failed: {res.status}")

Prediction Mode — 이게 꽤 중요하다

Magika의 디테일 중에 많이 간과되는 게 prediction mode다. 세 가지가 있다.

  • high-confidence (기본값): 모델이 충분히 확신하지 않으면 Generic text documentUnknown binary data 같은 fallback 레이블을 반환한다
  • medium-confidence: 중간
  • best-guess: confidence 낮아도 모델 예측을 그대로 내뱉는다

보안 파이프라인에서는 high-confidence가 기본값인 이유가 있다. 의심스러운 파일을 억지로 분류해서 잘못된 스캐너로 라우팅하는 것보다, 모른다고 솔직히 말하고 generic fallback으로 보내는 게 안전하다. 반면에 파일을 어떻게든 분류는 해야 하는 archival 작업이면 best-guess가 맞다.

Python에서는 이렇게 지정한다.

python
from magika import Magika, PredictionMode
 
m = Magika(prediction_mode=PredictionMode.BEST_GUESS)
python
from magika import Magika, PredictionMode
 
m = Magika(prediction_mode=PredictionMode.BEST_GUESS)

JavaScript/TypeScript — 브라우저에서도 된다

npm 패키지도 있는데, 이게 좀 재밌다. 브라우저에서 직접 돌아간다. 공식 웹 데모가 실제로 ONNX Runtime Web 위에서 모델을 WASM으로 실행한다. 서버로 파일 업로드 없이 클라이언트에서 바로 분류가 되는 거다.

javascript
import { Magika } from 'magika';
 
const m = await Magika.create();
const bytes = new Uint8Array(await file.arrayBuffer());
const result = await m.identifyBytes(bytes);
console.log(result.output.label);
javascript
import { Magika } from 'magika';
 
const m = await Magika.create();
const bytes = new Uint8Array(await file.arrayBuffer());
const result = await m.identifyBytes(bytes);
console.log(result.output.label);

프라이버시가 민감한 업로드 폼이나, 브라우저 extension에서 첨부파일 타입 검증하는 용도로 쓰기 좋아 보였다. 단, npm 패키지는 공식 문서에서도 "experimental"이라고 못 박고 있으니 프로덕션 의존성으로 넣을 때는 버전 고정을 권한다.

어떻게 동작하나 — 3×512 바이트의 마법

여기가 가장 흥미로운 부분이다. Magika는 파일 전체를 읽지 않는다. 정확히 세 구간에서 512바이트씩만 샘플링한다.

  • 파일 시작 512바이트
  • 파일 중간 512바이트
  • 파일 끝 512바이트

합쳐서 1.5KB. 이게 CNN의 입력이다. 10GB짜리 비디오 파일이든 100바이트짜리 설정 파일이든 추론 시간이 거의 일정한 이유가 여기에 있다. file 커맨드가 파일 헤더만 보는 것과 비슷한 발상이지만, 중간과 끝까지 본다는 점에서 content-based 판단을 더 잘 한다.

모델 아키텍처는 Keras로 학습되고 ONNX로 export된다. 학습 데이터는 논문 기준으로 GitHub + VirusTotal에서 수집한 24M 샘플로 113개 canonical content type을 학습했고, 1.0 릴리스에서는 더 확장돼서 200개 이상이 됐다. 모델 가중치는 약 1MB 수준이다. CPU 한 코어에서 돌아간다.

성능 숫자는 이렇다.

  • 평균 F1 스코어 99% (1.2M 홀드아웃 샘플 기준)
  • 단일 CPU 추론 5.77ms/파일 (bulk inference)
  • MacBook Pro M4 기준 초당 약 1,000파일

비교 대상인 libmagic의 file-mime이 F1 88%, TrID가 약 87%라는 걸 감안하면 격차가 꽤 크다. 특히 텍스트 콘텐츠에서 12% F1 향상이 나왔다. JSON, YAML, TOML, HCL처럼 구조는 비슷한데 의미가 다른 포맷들을 구별하는 데서 heuristic 방식이 약할 수밖에 없는데, 거기서 차이가 벌어진 것 같다.

1.0에서 뭐가 바뀌었나

가장 큰 변화는 Rust로 엔진 재작성이다. Python CLI가 있던 자리를 Rust native CLI가 완전히 대체했다. 내부적으로 ONNX Runtime + Tokio로 병렬 처리하는 구조다.

체감되는 변화:

  • 단일 코어에서 이전 대비 약 2배 빠름
  • 멀티코어 확장이 수월해짐 — Tokio async로 수천 파일/초 가능
  • Python 의존성 없이 단일 바이너리로 배포 가능

그리고 content type 커버리지가 눈에 띄게 넓어졌다.

  • Modern languages: Swift, Kotlin, TypeScript, Dart, Solidity, WebAssembly, Zig
  • Data Science / ML: Jupyter, NumPy, PyTorch, ONNX, Parquet, HDF5
  • DevOps: Dockerfile, TOML, HCL, Bazel, YARA rules

Kotlin이랑 Swift가 원래 빠져 있었다는 게 좀 놀라웠는데, 아마 학습 데이터에 있는 GitHub 샘플 분포 때문이었던 것 같다. 이번에 제대로 채웠다.

경쟁자와 비교 — 완벽하진 않다

솔직한 평가도 남겨둬야겠다. OPSWAT 벤치마크를 보면 Magika, TrID, libmagic을 결합했을 때가 어느 단일 도구보다 정확도가 높았다고 한다. 즉 Magika에도 blind spot은 있다.

대표적인 약점 하나는 UPX로 패킹된 PE 실행 파일이다. Magika나 TrID는 이걸 그냥 "PE executable"로 분류하는데, file 커맨드는 "UPX compressed"까지 짚어준다. 악성코드 분석처럼 패킹 여부가 중요한 시나리오에서는 file을 병행해서 쓰는 게 낫다.

그래서 내 결론은 "libmagic을 버려라"가 아니다. 파일 타입을 정확히 알고 싶을 때는 Magika, 포맷의 물리적 특징(압축, 인코딩 세부사항)을 알고 싶을 때는 file. 둘 다 쓰면 된다.

실제로 쓸만한가 — 내 판단

이번 주말에 사이드 프로젝트 하나에 적용해 볼 생각이다. 사용자가 업로드한 파일을 S3에 저장하기 전에 MIME 검증하는 훅이 있는데, 지금은 file 커맨드를 subprocess로 호출하고 있다. 브라우저 업로드 시점에서 확장자와 실제 content type이 불일치하는 케이스를 더 정밀하게 잡고 싶었다.

그리고 .parquet, .pt 같은 ML artifact를 받는 서비스가 점점 늘고 있는데, file 커맨드는 저런 걸 거의 못 잡는다. 여기서 Magika가 실질적으로 값을 할 것 같다.

한 가지 마음에 걸리는 건 model drift. 학습 데이터가 2024년 이전 GitHub 스냅샷이라면, 2026년에 나온 새 포맷이나 방언에 대해서는 여전히 "Unknown"으로 빠질 가능성이 있다. 모델 업데이트 주기가 공식 문서에 명시돼 있지 않은데, 이 부분은 이슈 트래커에서 좀 지켜봐야겠다.

전반적으로 지금까지 써본 file identification 도구 중에서 가장 인상에 남은 건 맞다. 특히 Apache 2.0 라이선스로 풀렸고, 모델까지 같이 공개되어 있어서 on-premise 보안 파이프라인에 붙이기 부담이 없다는 점이 좋았다.

참고 자료

YouTube 영상

채널 보기
내적의 기하학적 의미와 코사인 유사도 원리 | 선형대수학
인공지능은 세상을 어떻게 숫자로 읽는가? - 이미지, 소리 그리고 텍스트가 행렬이 되는 원리 | 선형대수학
투영과 예측, 그리고 선형 결합 | 선형대수학
AI 추천 시스템의 원리, 벡터 사이의 각도와 코사인 유사도 | 선형대수학
트라이(Trie) 자료구조: 파이썬으로 삽입(Insert) 연산 구현하기 | Trie 자료구조 이야기
트라이(Trie)를 이용한 자동 완성 알고리즘 | Trie 자료구조 이야기
스칼라 곱셈과 내적의 기하학적 의미 | 선형대수학
AI를 위한 선형대수학 - 소개 | 선형대수학