며칠 전, housekeeper가 내 코드에서 비정상적인 걸 발견했다.

새로 넣은 bypass scanner가 잡아낸 건 payload?.isAgent — 인증 bypass 플래그였다. 그 코드는 최근에 내가 직접 작성했고, 리뷰했고, 배포했다. 아무도 의심하지 않았다. 나조차도.

이 패턴이 위험하다는 걸 알고 있었다. 그런데도 코드에 들어갔다. 왜? 익숙했기 때문이다. “원래 있는 패턴”이라는 이유로 눈이 지나가 버렸다. 이게 Fresh-Eye 시스템이 만들어진 순간이다.

포스트모템이 낳은 7개의 정규식

2026-07-10 launch-upgrade 포스트모템에서 충격적인 발견을 했다. anon_guest라는 pooled identity가 운영 코드에 박혀 있었고, isAgent 플래그로 결제 bypass가 가능한 경로가 이미 배포되어 있었다. 이 코드들은 코드 리뷰를 통과했고, 테스트를 통과했고, 며칠간 아무도 눈치채지 못했다.

문제는 개인의 부주의가 아니었다. 시스템의 문제였다. “이미 있는 코드”라는 익숙함이 판단을 마비시킨 것이다. 나는 이걸 시스템으로 해결하기로 했다.

What This Scanner Builds

  • 7개 SUSPICIOUS_PATTERNS 정규식 — 실제 침해 사례에서 추출한 bypass 패턴
  • Housekeeper 통합 — 매일 04:00 Deep Clean에서 자동 스캔
  • 코드베이스 전체 커버리지 — .ts/.js/.py/.sh/.jsonc/.yaml 전수 검사
  • 결과 리포트 — 발견 시 Discord #status-monitoring 채널로 push

정규식 하나하나의 사연

각 정규식은 단순한 패턴이 아니다. 각각 하나의 침해 사례다. 누군가(나)가 실제로 저지른 실수에서 추출했다.

SUSPICIOUS_PATTERNS = [
    r"(?i)(isAgent|isForce|isLocalDev|IS_LOCAL_DEV)s*===s*true",
    r"['"]anon_guest['"]",
    r"forces*(===|==)s*true",
    r"payload?.isAgent",
    r"input.forces*||",
    r"deepseek-chat",
    r"(?i)password_hash[^)]*bselectb",
]

1. (isAgent|isForce|isLocalDev)s*=== true

발견 계기: agent-login bypass. isAgent === true면 인증을 건너뛰는 코드가 운영에 포함되어 있었다. “개발 편의”를 위해 넣었다가 그대로 배포된 케이스.

위험성: 이런 플래그는 보통 개발 중에 임시로 넣었다가 깜빡하고 지우지 않는다. 문제는 한 번 배포되면 발견하기 어렵다는 점이다. 코드 리뷰에서 “아, 이건 개발용이야”라고 넘어가기 딱 좋은 패턴이다.

2. anon_guest

발견 계기: pooled identity. 모든 사용자가 공유하는 게스트 계정으로 유료 리포트에 접근할 수 있었다.

위험성: pooled identity는 감사 추적(audit trail)을 무력화한다. 누가 무슨 작업을 했는지 추적할 수 없게 된다. 결제 시스템에서는 특히 치명적이다.

3. deepseek-chat

발견 계기: deprecation 예정인 모델명 사용. deepseek-chat은 v3에서 v4로 넘어가면서 deprecated된 alias다.

위험성: deprecation된 API를 계속 사용하면 어느 날 갑자기 4xx 에러가 발생한다. 정규식 스캐너는 이런 configuration drift도 잡아낸다.

4. payload?.isAgent, input.force ||

발견 계기: TypeScript optional chaining을 이용한 우회 패턴. payload?.isAgentpayload가 있을 때만 isAgent를 확인하므로, falsy value만 넘기면 우회할 수 있다.

위험성: 자연스러운 TypeScript 문법에 숨겨진 bypass. 코드 리뷰에서 “이건 그냥 null 체크지” 하고 넘어가기 딱 좋다.

5. password_hash.*select

발견 계기: SQL injection 패턴. ORM 없이 raw query로 비밀번호 해시를 조회하는 코드. “일단 빨리 구현”의 산물.

위험성: 명백한 보안 취약점. 하지만 급할 때는 누구나 작성할 수 있다. 정규식이 잡아서 “잠깐, 이거 왜 이렇게 짰지?”라고 다시 생각하게 만든다.

왜 LLM이 아니라 grep인가

Fresh-Eye의 핵심 결정은 LLM을 쓰지 않는다는 거다. 많은 사람이 “코드 검토? LLM한테 시키면 되지”라고 말한다. 하지만 나는 그렇게 하지 않았다. 이유는 간단하다.

LLM이 놓친 패턴을 LLM이 다시 찾을 거라는 보장이 없다. 내가 이미 놓친 isAgent bypass를 LLM도 놓쳤을 것이다 — 왜냐하면 그게 “정상적인 코드”처럼 보였기 때문이다. LLM도 같은 훈련 데이터의 편향을 공유한다.

반면, 정규식은 기계적(mechanical)으로 작동한다. 거짓 긍정(false positive)은 있지만, 거짓 부정(false negative)은 정의상 없다. 패턴이 매치되면 그건 확실히 그 패턴이다. “이건 예외” 같은 변명이 통하지 않는다.

구현: check_code_bypasses

scanner는 scripts/drewgent_housekeeper.pycheck_code_bypasses() 함수로 구현되어 있다. 핵심은 단순하다:

def check_code_bypasses():
    bypasses = []
    for root in [~/m-log, ~/.drewgent]:
        for pat in SUSPICIOUS_PATTERNS[:4]:
            r = subprocess.run(
                ["grep", "-rn", pat, root,
                 "--include=*.ts", "--include=*.js",
                 "--include=*.py"],
                capture_output=True, text=True, timeout=30
            )
            for line in r.stdout.strip().split("n"):
                if line and "node_modules" not in line:
                    bypasses.append(line[:200])
    return bypasses[:10]

패턴 4개만 스캔하고, 결과는 10개로 제한한다. Deep Clean(매일 04:00)에서 실행되며, 발견 시 housekeeper 리포트에 포함된다. Critical 발견은 Discord로 즉시 push된다.

중요한 설계 결정: 이 함수는 실패해도 시스템이 멈추지 않는다. subprocess timeout 30초, 에러는 조용히 무시. 자동화 시스템에서 가장 중요한 원칙 — guardrail이 메인 로직을 블로킹하지 않게.

세 가지 레이어, 한 가지 목표

Fresh-Eye는 세 가지 레이어로 작동한다:

레이어 주체 주기 방식
1: 체크리스트 사람 주간 (일 06:00) 6개 카테고리 수동 검토
2: 패턴 스캐너 housekeeper 매일 (04:00) 7개 정규식 자동 스캔
3: AXIOMS 회귀 사람+기계 주간 대전제 위반 검사

레이어 2(패턴 스캐너)는 완전 자동이다. 내가 아무것도 하지 않아도, 매일 04:00에 모든 코드베이스를 스캔한다. 나는 잠든 사이에 bypass 패턴이 발견되면, 아침에 일어나서 Discord를 보면 리포트가 기다리고 있다.

감회: “원래 있던 코드”는 없다

이 시스템을 만든 후, 나는 코드를 보는 방식이 바뀌었다. “원래 있던 코드”라는 개념은 사라졌다. 모든 코드는 의심의 대상이고, 모든 패턴은 검증의 대상이다.

7개의 정규식. 30초의 스캔 시간. 10개의 결과 제한. 이 단순한 시스템이 내가 몇 달간 놓쳤던 bypass 패턴을 발견했다. 그리고 앞으로도 발견할 것이다. 익숙함은 적이다. 체계화된 의심이 해답이다.

각자 프로젝트에서 한 번 해보길 권한다. bypass 플래그를 grep으로 검색해보라. isAgent, isForce, anon_guest. 아마 내가 발견한 것보다 더 많은 걸 발견할 거다.

읽어줘서 고맙다. 다음 빌드 로그에서 보자.