한 줄 요약: Base64로 감춘 Bash와
eval은 티셔츠 이스터에그여도 공급망 보안 문제처럼 보일 수 있다. 쟁점은 코드가 악성이냐보다, 사람이 확인하기 전에 실행되는 흐름을 어디까지 허용할지에 가깝다.
왜 지금 이슈인가
난독화된 Bash script, eval, Base64, 공급망 보안은 보안팀만 보는 단어가 아니다. 개발자는 문서, README, 설치 스크립트, CI 설정, SaaS 연동 가이드에서 이런 실행 경로를 자주 만난다.
이번 글감은 조금 엉뚱한 곳에서 시작됐다. Akamai가 UNIQLO Peace for All 캠페인 티셔츠 뒷면에 실제 코드를 넣었고, 그 코드는 Base64 문자열을 디코딩해 Bash 스크립트로 실행하는 형태였다. 디코딩하면 터미널에서 Peace for All 문구를 사인파처럼 출력하는 이스터에그가 나온다.
문제는 결과가 착하다는 사실만으로 끝나지 않는다. 형태만 보면 많은 사람이 경계하는 패턴과 닮았다.
eval "$(base64 --decode <<< "$payload")"
이 패턴은 짧고, 복사하기 쉽고, 설명하기도 쉽다. 그래서 설치 스크립트, 데모, CTF, 악성코드, 장난 코드에서 모두 보인다. 커뮤니티가 반응한 이유도 코드 한 줄의 위험 때문만은 아니다. 신뢰할 수 있는 브랜드, 익숙한 유통 경로, 보기 좋은 디자인, 복사 가능한 문자열이 한곳에 모이면 사용자는 코드를 읽기 전에 실행부터 해보고 싶어진다.
비슷한 긴장은 장치 식별자(Device ID) 논쟁에서도 보인다. PCMag가 보도한 Microsoft Device ID 추적 논란은 특정 제품에 대한 호불호를 넘어서, 사용자가 직접 의식하지 못하는 식별자와 로그가 수사, 계정, 플랫폼 정책과 연결될 수 있다는 불편함을 건드렸다.
두 사례는 성격이 다르지만 같은 질문으로 이어진다.
내가 보고 있는 것이 단순한 텍스트인지, 실행 가능한 코드인지, 식별 가능한 데이터인지 시스템은 어디서 구분하는가?
커뮤니티에서 갈리는 지점
첫 반응은 보통 관대하다. 이 티셔츠 코드는 실제로 귀엽고, 디코딩된 스크립트도 공격적이지 않다. tput으로 커서를 숨기고, bc로 사인 값을 계산하고, 256색 컬러로 글자를 찍는 터미널 애니메이션이다. trap으로 CTRL+C를 눌렀을 때 커서를 복원하는 처리도 들어 있다.
그런데 보안 감각이 있는 사람은 다른 부분을 먼저 본다.
- Base64는 암호화가 아니라 인코딩이지만, 사람이 바로 읽지 못하게 만든다.
eval은 문자열을 코드로 바꿔 현재 셸에서 실행한다.- 무한 루프는 의도와 상관없이 터미널 상태를 망칠 수 있다.
- 시각적 매체에 담긴 코드는 OCR 과정에서 한 글자만 틀려도 다른 코드가 된다.
- 브랜드가 공급한 코드라는 사실이 검증을 대신하지 않는다.
여기서 의견이 갈린다.
| 관점 | 주장 | 실무에서 남는 질문 |
|---|---|---|
| 재미있는 해커 문화 | 실제 코드를 물리 상품에 넣은 이스터에그 | 사용자가 실행해도 되는 코드를 어떻게 표시할 것인가 |
| 보안 경계 | 난독화와 eval 조합은 교육적으로 좋지 않은 예 | 샘플 코드에도 보안 기준을 적용해야 하는가 |
| 마케팅 관점 | Linux와 인터넷 문화에 대한 상징적 표현 | 기술 설명이 부정확할 때 신뢰는 어떻게 흔들리는가 |
| 플랫폼 관점 | 텍스트, 코드, 식별자가 유통 경로를 건너 이동한다 | 어느 지점에서 검증과 감사 로그를 붙일 것인가 |
선정 글감에서 재미있는 부분은 코드 자체보다 검증 과정이다. 작성자는 Android OCR, Tesseract, Claude 결과를 서로 비교하고, 불일치 지점을 표로 확인해 문자열을 복원했다. 장난감을 해부하는 과정처럼 보이지만, 실제 운영에서도 비슷한 일이 생긴다.
현업에서 외부 설치 가이드를 검토하다 보면 위험한 코드는 늘 노골적인 악성 형태로 오지 않는다. curl | sh, 압축된 YAML, 복사 붙여넣기용 토큰, SaaS 콘솔에서 내려받은 에이전트 설치 스크립트처럼 정상 업무의 얼굴을 하고 들어온다.
SLSA가 소프트웨어 공급망을 소스, 빌드, 출처 증명(provenance) 관점에서 보려는 이유도 여기에 있다. 코드를 누가 작성했는지만으로는 부족하다. 어떤 경로로 생성됐고, 어떤 절차로 검증됐고, 실행 시점에 무엇으로 바뀌는지까지 이어서 봐야 한다.
아키텍처 관점에서 볼 점
난독화된 스크립트를 다룰 때 첫 원칙은 실행과 해석을 분리하는 것이다. 읽기 전용 분석, 격리 실행, 신뢰 결정, 배포 승인을 한 흐름에 섞으면 사고가 나기 쉽다.
flowchart LR
A[외부 코드 입력<br/>README, 티셔츠, 설치 스크립트, SaaS 가이드] --> B{실행 가능한가?}
B -->|아니오| C[문서로 보관]
B -->|예| D[디코드와 정적 분석]
D --> E{위험 패턴 존재?}
E -->|eval, curl|sh, 난독화| F[격리 샌드박스 실행]
E -->|낮음| G[리뷰 기록 생성]
F --> H[네트워크, 파일, 프로세스 행위 관찰]
H --> I{정책 통과?}
G --> I
I -->|통과| J[제한된 권한으로 사용]
I -->|실패| K[차단 또는 대체 구현]
여기서 핵심은 Base64 자체를 금지하는 게 아니다. Base64는 바이너리나 긴 문자열을 옮길 때 흔히 쓴다. 위험 신호는 Base64 뒤에 바로 실행이 붙을 때 커진다.
예를 들어 다음 흐름은 검토할 여지가 있다.
decoded=$(base64 --decode <<< "$payload")
printf '%s\n' "$decoded"
shellcheck /tmp/script.sh
반대로 다음 흐름은 사람이 개입할 틈을 줄인다.
eval "$(base64 --decode <<< "$payload")"
eval이 필요한 상황도 있다. 동적으로 명령을 조립해야 하는 오래된 스크립트, 제한된 환경의 부트스트랩 코드, 셸 메타프로그래밍이 그런 예다. 다만 운영 환경에서 eval을 설계의 중심에 두면 검증 지점이 줄어든다.
아키텍처 관점에서는 다음 세 가지를 나눠 봐야 한다.
| 확인 지점 | 질문 | 실패했을 때 생기는 문제 |
|---|---|---|
| 입력 무결성 | 문자열이 원본 그대로인가 | OCR, 복사, 줄바꿈 오류로 다른 명령 실행 |
| 실행 권한 | 어떤 사용자와 환경에서 도는가 | 홈 디렉터리, SSH 키, 토큰 접근 |
| 행위 관찰 | 네트워크와 파일 접근을 볼 수 있는가 | 설치 후 무엇을 바꿨는지 추적 불가 |
티셔츠 코드는 네트워크 호출도 없고, 파일을 지우지도 않는다. 하지만 같은 패턴이 CI에서 실행되면 이야기가 달라진다. CI에는 배포 키, 패키지 토큰, 클라우드 권한이 붙어 있다. 로컬 터미널에서 귀여운 애니메이션이던 코드가 GitHub Actions나 사내 빌드 러너에서는 공급망 공격 표면이 된다.
ShellCheck 같은 도구는 여기서 1차 필터 역할을 한다. 따옴표 누락, 위험한 변수 확장, 흔한 셸 실수를 잡아준다. 하지만 도구가 의도를 판정해주지는 않는다. eval이 있는지 알려줄 수는 있어도, 그 eval을 받아들일지 말지는 팀의 정책과 실행 맥락이 결정한다.
실무에서 볼 점
도입 전에 먼저 볼 것은 기술보다 경로다. 코드가 어디서 왔고, 누가 복사했고, 어떤 권한으로 실행되는지다.
외부 스크립트를 받아야 한다면 최소한 이 정도는 분리하는 편이 낫다.
- 디코딩 단계와 실행 단계를 분리한다.
- 실행 전에 사람이 읽을 수 있는 파일로 저장한다.
- 네트워크가 막힌 컨테이너나 VM에서 먼저 돌린다.
- 실행 사용자 권한을 낮춘다.
- CI에서는 외부 스크립트에 장기 토큰을 노출하지 않는다.
- 설치 스크립트 버전, 해시, 출처 URL을 기록한다.
NIST SSDF가 말하는 secure software development도 결국 이런 검증 가능한 절차를 요구한다. 외부 컴포넌트와 도구를 식별하고, 변경을 추적하고, 취약점과 무결성 문제를 관리해야 한다. 긴 보안 문서보다 실행 가능한 체크포인트가 먼저다.
실제로 이런 상황은 금지 목록만으로 해결하기 어렵다. curl | sh를 금지해도 사용자는 설치 문서를 따라 다른 방식으로 우회한다. Base64를 막아도 gzip, heredoc, 압축 아카이브, 바이너리 인스톨러가 남는다.
더 나은 접근은 위험도에 따라 문턱을 다르게 두는 것이다.
| 상황 | 허용 기준 |
|---|---|
| 개인 로컬 실험 | 디코딩 후 눈으로 확인, 낮은 권한 실행 |
| 팀 개발 환경 | 리뷰된 스크립트만 저장소에 커밋 |
| CI/CD | 고정 버전, 해시 검증, 비밀값 최소 노출 |
| 프로덕션 노드 | 외부 동적 스크립트 직접 실행 금지 |
| 보안 민감 조직 | provenance, SBOM, 승인된 아티팩트 저장소 사용 |
Device ID 논쟁도 같은 기준표로 볼 수 있다. 식별자 자체가 항상 나쁜 것은 아니다. 라이선스, 사기 방지, 동기화, 보안 이벤트 추적에 필요할 수 있다. 문제는 사용자가 이해한 목적과 실제 사용 경로가 어긋날 때다.
코드도 마찬가지다. 이스터에그 코드는 문화가 될 수 있다. 설치 스크립트도 생산성을 높인다. 다만 실행 가능한 텍스트가 신뢰 경계를 넘을 때는 재미, 편의, 운영 효율 중 무엇을 우선할지 먼저 정해야 한다.
팀에서 당장 해볼 만한 점검은 간단하다.
rg "eval|curl .*sh|base64 --decode|bash -c|sh -c" .
이 검색은 범인을 찾는 도구가 아니다. 자동 실행되는 문자열 코드가 어디에 숨어 있는지 지도를 만드는 출발점이다. 발견된 항목마다 왜 필요한지, 대체할 수 있는지, 권한을 낮출 수 있는지 보면 된다.
정리
Akamai 티셔츠의 Bash 이스터에그는 해롭지 않은 코드다. 그래서 사례로 보기 좋다. 큰 사고가 난 뒤에야 공급망 보안을 말하면 대화가 방어적으로 흐르지만, 이런 사례는 같은 구조를 낮은 긴장 속에서 살펴볼 수 있다.
실무 판단은 한 문장으로 정리된다. 사람이 읽기 전에는 실행하지 말고, 실행해야 한다면 권한과 관찰 범위를 먼저 줄여야 한다.
오늘 확인할 것은 하나면 충분하다. 우리 저장소와 CI 설정에 eval, curl | sh, Base64 디코드 후 실행이 어디에 있는지 찾아보고, 그중 하나만 디코딩 단계와 실행 단계를 분리해보자. 공급망 보안은 이런 작은 경계선에서 시작된다.
참고 자료
- [선정 글감] Obfuscated bash script by Akamai being supplied to consumers via retail stores — Lobsters
- [관련] Microsoft Can Track Users via a Windows Device ID — PCMag
- [관련] SLSA Framework — SLSA
- [관련] Secure Software Development Framework SP 800-218 — NIST
- [관련] ShellCheck — ShellCheck

댓글