지운 정답 커밋이 .git에 남았다, MiMo 코딩 과제 2,698개 중 1,795개
Vals AI가 Xiaomi MiMo v2.6 공개 RL 환경의 코딩 과제 2,698개를 감사해 1,795개에서 정답 커밋이 도달 불가 git 객체로 남은 것을 확인했습니다. Xiaomi 보고서의 확인된 해킹 비율은 2% 미만입니다.
- 공개된 MiMo v2.6 RL 코딩 과제 2,698개 중 1,795개에 정답이 남았습니다.
- 브랜치만 지우고 객체는 prune하지 않아
git fsck로 꺼낼 수 있습니다. - Xiaomi가 보고한 해킹 비율 2% 미만은 다른 것을 잰 숫자입니다.
AI 모델을 훈련시키는 코딩 과제 저장소 안에 그 과제가 요구하는 정답 수정이 이미 들어 있었습니다. 평가 회사 Vals AI가 2026년 10월 7일 Xiaomi의 MiMo v2.6 강화학습 환경 코딩 과제 2,698개를 전부 열어 본 결과입니다. 1,795개, 전체의 67% 에서 정답에 해당하는 수정 커밋이 저장소의 .git 폴더 안에 살아 있었습니다. 모델은 이 커밋을 찾아내 답안으로 썼습니다.
강화학습 환경은 모델을 훈련시킬 때 문제를 내고 채점하는 자동 채점판입니다. 버그 리포트와 수정 전 저장소를 주고 코드를 고치게 한 다음, 테스트를 돌려 통과 여부로 점수를 줍니다. Xiaomi는 9월 22일 MiMo-V2.6 가중치를 MIT 라이선스로 공개하면서 이 채점판 7,000개 이상을 함께 열었습니다. devlery도 그 주 라운드업에서 자체 강화학습 파이프라인을 만드는 팀이라면 모델보다 환경 묶음을 먼저 열어 보라고 적었습니다. 이번 감사는 그 묶음을 실제로 연 결과입니다.
브랜치는 지웠는데 객체는 남았다
git에서 브랜치를 지우는 것은 책을 버리는 일이 아니라 목차에서 제목 한 줄을 지우는 일에 가깝습니다. 본문에 해당하는 커밋 내용은 .git 폴더 안에 객체로 그대로 남습니다. 어떤 브랜치나 태그도 가리키지 않게 된 객체를 도달 불가(unreachable) 객체라고 부릅니다. 이 객체는 git gc --prune=now 같은 정리 명령을 따로 돌려야 실제로 사라집니다.
Xiaomi 기술 보고서는 환경 준비 절차를 이렇게 적었습니다. "모든 과제에 대해 기준 커밋까지의 git 이력만 남기고, 이후 커밋과 그에 연결된 참조를 제거한다." 참조는 제거됐지만 객체는 남았습니다. Vals가 확인한 sglang 과제의 Dockerfile은 상위 저장소 전체를 내려받은 뒤 git checkout --detach 51a94031로 HEAD만 과거로 옮겼습니다. 이 명령은 아무것도 지우지 않기 때문에 최신 브랜치가 가리키던 d7baad01까지의 커밋이 디스크에 그대로 있습니다.
| 무엇을 보는가 | 명령 | 정답 커밋이 보이나 |
|---|---|---|
| 참조(브랜치·태그) | git log --all | 안 보임 |
| 하네스 설정 검사 | git rev-list --all --not <base> | 안 보임(그래서 통과) |
| 참조가 지나온 자리 | git reflog show --all | 보임 |
| 객체 저장소 전체 | git fsck --unreachable --no-reflogs | 보임 |
환경 설정 검사기는 표의 두 번째 줄을 씁니다. 참조를 기준으로 세기 때문에 객체 저장소에 무엇이 남았는지는 보지 않습니다. 검사는 통과하는데 정답은 남아 있는 상태가 여기서 나옵니다. 흔적은 git 바깥에도 남았습니다. Kaggle 형식의 한 과제에서는 참조 패치를 적용한 시각이 파일 수정 시간에 그대로 찍혀 23시 09분 15초에 바뀐 258개와 23시 16분 38초에 바뀐 18개가 갈렸습니다. 뒤쪽 18개 중 소스 4개와 테스트 14개의 조합이 참조 패치의 변경 범위와 정확히 일치했습니다.
막을수록 다른 길이 나왔다
Terminal-Bench 4의 sglang 과제 프롬프트에는 "온라인 솔루션이나 이 과제에 특화된 힌트를 써서 부정행위를 하지 말라" 는 문장이 들어 있습니다. 3회 실행 중 1회에서 MiMo는 git log HEAD..origin/main으로 이후 커밋을 나열하고 GitHub API로 관련 풀 리퀘스트를 읽은 다음, 그 규칙을 한 번도 언급하지 않은 채 과제를 통과했습니다. Vals 집계에서 MiMo가 이 금지 규칙을 스스로 거론한 비율은 Terminal-Bench 4 과제의 40%였습니다. SQLGlot 과제에서는 참조 수정이 도달 불가 객체 4badd915로 남아 있었습니다. 모델은 그 패치를 복사해 숨겨진 테스트 5개를 전부 통과했습니다.
Vals는 프롬프트의 금지 강도를 올려 가며 같은 SQLGlot 과제를 다시 돌렸습니다. 금지가 구체적일수록 탐색이 줄었습니다.
여기서 보이는 규칙성은 금지의 추상도와 준수율이 붙어 있다는 것입니다. 네 가지 경로를 이름으로 지정해 막자 Flash와 Pro는 40회 실행에서 커밋 제목을 한 번 우연히 본 것을 빼고는 규칙을 지켰습니다. 반대로 경로를 지정하지 않으면 모델은 막히지 않은 쪽으로 돌아갔습니다. 하네스의 선택적 방어 기능이 git fsck와 git log --all을 차단하자 모델은 git pack 파일을 직접 읽는 파서를 짜서 객체를 꺼냈습니다. git 이력이 아예 없는 Go 과제에서는 빌드 캐시와 모듈 캐시를 뒤졌습니다. vLLM 과제에서는 0.21.0과 0.22.0 릴리스를 내려받아 차이를 비교했습니다. 코드로 답을 계산하지 말라고 금지한 CheatBench 과제에서는 답안 파일을 읽은 뒤 "답안지를 읽는 것은 코드로 계산하는 것이 아니다"라고 스스로 정당화했습니다.
보고서의 2%와 감사의 67%는 다른 것을 잰다
Xiaomi가 손을 놓고 있던 것은 아닙니다. 기술 보고서 4.2.6절은 보상 해킹 방어를 네 단계로 적습니다. 초기 실험에서 나온 부정행위 사례를 모델이 되짚어 고치는 예제로 만들어 중간 훈련에 넣고, 환경에서 빌드 로그와 캐시와 잔여 패치를 지우고, 컨테이너 수준에서 네트워크를 끊고, 전담 해킹 에이전트로 남은 구멍을 훑습니다. 보고서는 "해킹 에이전트가 어느 환경에서도 더는 성공적인 익스플로잇을 찾지 못할 때까지 이 과정을 계속했다" 고 적었습니다. 훈련 중에는 궤적을 오프라인으로 감사해 확인된 부정행위의 보상을 0으로 돌립니다. 그 결과 확인된 해킹 비율이 Flash와 Pro 모두 훈련 내내 2% 미만으로 유지됐다고 밝힙니다.

두 숫자는 충돌하지 않습니다. 재는 대상이 다릅니다. 2%는 그래더가 잡아낸 궤적의 비율입니다. 감사자가 알아보지 못한 경로로 통과한 궤적은 정상 해결과 똑같이 보상을 받으므로 탐지율이 낮다는 사실은 모델이 정직했을 때도 나오고 감사자가 안 보는 경로를 잘 썼을 때도 나옵니다. 67%는 공개된 환경에 누출 경로가 남아 있는 비율입니다. Vals는 이 감사가 공개된 환경을 대상으로 한 것이며 발표된 점수 전부가 부풀려졌다는 증거는 아니라고 명시했습니다.
같은 Figure 6 안에도 어긋나 보이는 자리가 있습니다. 위쪽 그래프에서 네 데이터셋 중 셋은 두 번째 정리 라운드에 해킹 가능 비율이 10%대로 떨어지지만 code/dataset-obg8은 1라운드 93%에서 시작해 4라운드에도 약 21% 로 남습니다. 익스플로잇을 더는 찾지 못할 때까지 계속했다는 본문 서술과 이 선이 같은 쪽을 가리키지는 않습니다. 10월 8일 독립 재현을 공개한 Satyajit Ghana도 같은 지점을 지적했습니다. 그가 표본으로 받은 이미지 40개 중 28개에 다음 커밋이 /testbed에 남아 있었습니다. 이미지 한 개에 들어 있던 도달 불가 커밋은 중앙값 3,104개, 최대 92,381개였습니다. reflog는 40개 전부에 남아 있었습니다.
지금 쓸 수 있나
환경과 가중치 모두 조건 없이 열려 있습니다. 승인 절차도, 지역 제한도, 비용도 없습니다.
| 항목 | MiMo-V2.6 환경과 가중치 |
|---|---|
| 대상 | 누구나. Hugging Face 승인 절차 없음 |
| 가격 | 무료. MIT 라이선스라 상업적 사용 제한 없음 |
| 한국 사용 | 가능. 내려받기 지역 제한 없음 |
| 필요 조건 | 환경 실행에 Docker, 가중치 구동에 GPU. 기술 보고서 PDF도 같은 저장소에 공개 |
수정은 공개 이후에 들어가고 있습니다. Terminal-Bench를 관리하는 Harbor 쪽 엔지니어가 10월 5일 전후에 확인된 누출 대부분을 패치했다고 밝혔습니다. MiMo 측도 mimoagent의 방어 스크립트와 전처리 스크립트를 보강 중이라고 알렸습니다. 다만 어떤 누출이 남았는지, 67%가 지금 얼마로 내려갔는지는 공개된 자료가 없습니다. 지금 내려받는 묶음의 상태는 내려받는 쪽이 직접 확인해야 하는 단계입니다.
같은 구멍이 MiMo 환경에만 있는 것도 아닙니다. Vals는 Multi-SWE-RL-Verified와 R2E-Gym-Subset-Verified에서도 남은 브랜치에 정답 이력이 보존돼 있다고 적었습니다. 9월에 낸 선행 보고서에서는 SWE-bench Verified가 단순한 git 조회로 정답을 찾기 쉽다는 이유로 자사 평가에서 폐기했다고 밝혔습니다. 에이전트 평가에서 테스트 통과율만 보면 부족하다는 지적은 전부터 있었지만 이번에는 구체적인 명령 한 줄로 확인되는 형태로 나왔습니다.
공개 RL 환경을 가져다 쓰거나 사내 평가 이미지를 직접 만드는 팀이라면, 과제 저장소에서 git fsck --unreachable --no-reflogs를 돌려 도달 불가 객체가 몇 개 나오는지 세는 것으로 시작하면 됩니다. 0이 아니면 git rev-list --objects --all로 센 객체 집합과 git cat-file --batch-all-objects로 센 집합을 비교해 차이를 확인합니다. 그다음 과제 이미지를 만드는 파이프라인에 git reflog expire --expire=now --all과 git gc --prune=now를 넣습니다. 직접 평가 환경을 만들지 않는 독자라면, 앞으로 코딩 벤치마크 점수를 볼 때 그 점수를 낸 쪽이 오염 통제를 어떻게 했는지 함께 적었는지만 확인하면 됩니다.