
Severity: High
Reporter: ihopenre-eng
Published: July 2026
최근 제가 Oh My Posh 프로젝트에서 보고한 취약점이 GitHub Security Advisory(CVE-2026-73505)로 공개되었습니다.
이번 취약점은 단순한 템플릿 처리 문제가 아니라, 사용자가 현재 위치한 디렉터리 이름을 다시 Go text/template 엔진으로 렌더링하는 과정에서 발생했습니다.
디렉터리 이름에 Go Template 표현식을 포함하면, 프롬프트가 렌더링되는 시점에 해당 표현식이 실행됩니다. 특히 템플릿 함수(cmd)를 통해 운영체제 명령을 실행할 수 있어 현재 사용자 권한으로 임의 명령 실행(Arbitrary Command Execution) 이 가능했습니다.
이번 글에서는 취약점을 분석하면서 어떤 코드가 원인이 되었는지, 실제로 어떻게 명령 실행으로 이어졌는지 살펴보겠습니다.
여기서는 먼저 Path Segment가 어떻게 생성되는지 설명합니다.

처음 의심했던 부분

처음에는 이 코드가 단순히 설정 파일에 포함된 템플릿만 처리하는 것으로 생각했습니다.
하지만 pt.Path가 어디에서 만들어지는지 계속 따라가 보니 조금 다른 모습을 확인할 수 있었습니다.

folder name이
fmt.Sprintf(folderFormat, element)
로 들어가는 부분.
element는 현재 작업 디렉터리의 실제 폴더 이름입니다.
즉,
hello
도 들어가고
{{ cmd `whoami` }}
같은 문자열도 그대로 들어갑니다.
여기가 핵심입니다.

여기서
이미 사용자 입력이 포함된 문자열을 다시 Template Engine으로 해석하고 있었습니다.

템플릿 엔진에는 여러 함수가 등록되어 있는데,
그중 cmd()는 운영체제 명령을 실행하는 함수입니다.
즉,
{{ cmd "whoami" }}
가 Template 안에서 실제 명령을 실행합니다.

이 그림 하나 있으면 이해가 엄청 쉬워집니다.

프롬프트를 렌더링하는 순간
whoami
명령이 실행되고
출력이 Prompt에 그대로 반영됩니다.
powershell

실행 후
pwn3d
파일 생성.
영향
여기서 실제 공격 시나리오.
Git Clone
ZIP 압축
USB
Network Share
사용자가
cd
하는 순간
Prompt Rendering
↓
Command Execution
패치
패치 Diff.
여기서
Template.Render 제거
또는
Escape
되는 부분.
이 취약점은 Go Template 자체의 문제가 아니라 신뢰할 수 없는 데이터를 Template로 다시 해석(Double Evaluation) 한 것이 원인이었습니다.
템플릿 엔진는 설정 파일처럼 신뢰할 수 있는 입력을 처리할 때는 매우 유용하지만, 사용자나 파일시스템에서 가져온 문자열을 그대로 다시 렌더링하면 의도하지 않은 코드 실행으로 이어질 수 있습니다.
이번 사례는 "데이터와 템플릿을 명확히 구분해야 한다"는 기본 원칙이 얼마나 중요한지를 보여주는 사례라고 생각합니다.