
Consul Template의 writeToFile 헬퍼는 운영자가 제공한 대상 경로를 직접 열고 링크된 경로 구성 요소를 따라가며, 렌더링된 출력이 의도된 디렉터리를 벗어나 기존 파일을 덮어쓸 수 있게 했습니다.
Consul Template의 writeToFile 헬퍼는 운영자가 지정한 대상을 직접 열고 연결된 경로 구성 요소를 따르므로, 렌더링된 출력이 의도된 디렉터리를 벗어나 기존 파일을 덮어쓸 수 있습니다.
저는 HashiCorp Consul Template을 검토하면서 다음과 같은 직접적인 파일시스템 보안 질문을 염두에 두고 이 문제를 발견했습니다:
writeToFile이 의도된 디렉터리 안에 있는 것처럼 보이는 경로를 받으면, 파일시스템이 실제로 데이터를 기록할 위치를 검증합니까?
이 경우, 답은 "아니오"였습니다.
writeToFile 템플릿 헬퍼는 최종 사용자 제공 경로를 os.Create() 또는 os.OpenFile()을 통해 직접 열었습니다.
이러한 작업은 대상 경로에 이미 존재하는 심볼릭 링크, 디렉터리 정션 및 이에 상응하는 파일시스템 리다이렉션을 따라갔습니다.
즉, 경로 문자열은 운영자가 의도한 루트 아래에 유지될 수 있는 반면 실제 쓰기는 다른 곳에 발생할 수 있었습니다.
제가 통제한 개념 증명(PoC)에서는 연결된 부모 디렉터리가 렌더링된 출력을 의도된 트리 밖으로 리다이렉션하여 기존 대상 파일이 덮어써졌습니다.
이 문제는 CVE-2026-14361이 되었습니다.
HashiCorp 공지: HCSEC-2026-20
IBM 공지: CVE-2026-14361 보안 공지
CVE: CVE-2026-14361
수정 버전: 0.42.1
photo0
운영자가 지정한 대상이 의도된 루트 안에 나타남 -> 공격자가 연결된 부모 또는 최종 경로 구성 요소를 사전 배치 -> writeToFile이 경로를 직접 열음 -> 파일시스템이 의도된 디렉터리 밖으로 쓰기를 해석 -> 렌더링된 비밀이 리다이렉션됨 -> 기존 대상이 덮어써질 수 있음
Consul Template은 Consul 및 Vault와 같은 소스의 데이터를 렌더링합니다.
writeToFile 헬퍼를 사용하면 템플릿이 선택한 콘텐츠를 요청된 소유자, 그룹 및 권한 모드를 적용하면서 별도의 로컬 파일에 쓸 수 있습니다.
HashiCorp 문서는 특히 PKI 자료와 함께 이 헬퍼를 시연합니다:
private key -> writeToFile /my/path/to/cert.key
certificate authority -> writeToFile /my/path/to/cert.pem
certificate -> append to /my/path/to/cert.pem
이로 인해 이 헬퍼는 단순한 출력 헬퍼 그 이상입니다.
이 경계를 통과하는 콘텐츠에는 다음이 포함될 수 있습니다:
중요한 질문은 writeToFile이 요청된 파일 이름을 생성할 수 있는지가 아니었습니다.
진짜 질문은 다음과 같았습니다:
프로세스가 운영자가 의도한 파일시스템 위치에 쓰는가, 아니면 열기 시점에 경로가 해석되는 대상 객체에만 쓰는가?
취약한 버전에서는 후자를 신뢰했습니다.
쓰기 헬퍼는 애플리케이션 데이터에서 파일시스템 변형으로 넘어가기 때문에 보안 가치가 높은 표면입니다.
흥미로운 실패는 종종 전형적인 ../ 경로 탐색이 아닙니다.
이는 해석(resolution) 실패입니다:
이는 프로세스가 공격자보다 더 많은 파일시스템 권한으로 실행될 때 특히 중요합니다.
권한이 낮은 로컬 공격자는 민감한 파일을 직접 덮어쓸 수 없을 수 있습니다.
그러나 의도된 쓰기 디렉터리 아래의 경로 구성 요소에 영향을 줄 수 있다면, 더 높은 권한의 Consul Template 프로세스가 대신 쓰기를 수행할 수 있습니다.
그것이 제가 집중한 경계였습니다.
저는 이를 일반적인 경로 탐색 검토로 접근하지 않았습니다.
제공된 경로에는 .. 세그먼트가 필요하지 않았습니다.
그 경로는 항상 어휘적으로 의도된 루트 안에 유지될 수 있었습니다.
더 강력한 질문은 다음과 같았습니다:
민감한 콘텐츠가 기록되기 전에 연결된 대상 구성 요소가 거부됩니까?
이 질문은 다음 두 가지 모두에 중요합니다:
두 번째 경우는 로그와 구성에 여전히 예상 디렉터리 아래의 무해해 보이는 경로가 표시되기 때문에 특히 유용합니다.
파일시스템은 그것을 다른 곳에서 해석합니다.
근본 원인은 링크 인식 검증 없이 경로 기반으로 직접 파일을 생성한 것이었습니다.
테스트한 리비전에서 writeToFile()은 두 가지 열기 경로 중 하나를 선택했습니다.
추가(append) 모드는 다음을 사용했습니다:
f, err = os.OpenFile(
path,
os.O_APPEND|os.O_WRONLY|os.O_CREATE,
perm,
)
일반 쓰기 모드는 다음을 사용했습니다:
dirPath := filepath.Dir(path)
if _, err := os.Stat(dirPath); err != nil {
err := os.MkdirAll(dirPath, os.ModePerm)
if err != nil {
return "", err
}
}
f, err = os.Create(path)
두 경로 모두 파일이 열리기 전에 연결된 대상 구성 요소를 거부하지 않았습니다.
이것이 중요한 이유는 다음과 같습니다:
os.Create(path)는 기존 파일시스템 리다이렉션을 따르고 해석된 파일을 잘라냅니다(truncate)os.OpenFile(path, ...)는 추가(append) 모드에서 연결된 경로 구성 요소를 따릅니다동일한 경로 기반 가정은 쓰기 이후에도 계속되었습니다.
소유권과 권한은 경로를 다시 사용하여 적용되었습니다:
err = os.Chown(path, uid, gid)
err = os.Chmod(path, perm)
즉, 메타데이터 작업도 이미 열린 파일 디스크립터 대신 변경 가능한 경로 이름에 묶여 있었습니다.
공격자는 writeToFile이 실행되기 전에 리다이렉션을 준비할 수 있기 때문입니다.
기본 공격에는 확률적 경쟁 조건(race)이 필요하지 않습니다.
순서는 간단합니다:
writeToFile이 그것을 직접 엶그것이 전체 취약점입니다.
운영 체제가 경로 기반 파일 열기 중에 일반적으로 심볼릭 링크를 따른다는 것은 사실입니다.
그렇다고 해서 이것이 안전한 애플리케이션 동작이 되는 것은 아닙니다.
보안 질문은 다음과 같은 것이 아닙니다:
"Go가 문서화된 대로 동작했는가?"
진짜 질문은 다음과 같습니다:
민감한 렌더링 데이터를 쓰는 헬퍼가 해석된 대상이 운영자가 의도한 위치와 일치하는지 검증했는가?
취약한 버전에서는 그렇게 하지 않았습니다.
이 구분이 중요한 이유는 Consul Template이 다음과 같이 실행될 수 있기 때문입니다:
그러한 맥락에서 공격자가 배치한 파일시스템 리다이렉션을 따르는 것은 실제 권한 및 신뢰 경계 문제를 만듭니다.
저는 테스트한 커밋의 정확한 writeToFile 동작을 중심으로 독립형 재현기를 구축했습니다.
통제된 설정은 다음을 사용했습니다:
writeToFile에 전달된 통제된 비밀 콘텐츠재현 흐름은 다음과 같았습니다:
관찰된 동작은 다음과 같았습니다:
writeToFile이 리다이렉션을 따랐습니다이로써 주장의 두 부분이 모두 입증되었습니다:
최종 구성 요소 심볼릭 링크만으로도 안전하지 않은 링크 따라가기를 입증할 수 있습니다.
그러나 연결된 부모 구성 요소는 더 강력한 운영적 요점을 증명합니다:
기존 대상도 중요했습니다.
그것이 없었다면 PoC는 예상치 못한 파일 생성만 보여주었을 것입니다.
기존 파일로 시작하고 최종 해시를 검증함으로써 재현은 덮어쓰기 동작을 직접 증명했습니다.
그로 인해 결과는 소스 전용 주장보다 더 구체적이었습니다.
이 문제는 로컬 파일시스템 영향력이 필요합니다.
공격자는 의도된 쓰기 위치 또는 그 아래에 심볼릭 링크, 디렉터리 정션 또는 이에 상응하는 리다이렉션을 생성하거나 수정할 수 있는 충분한 액세스 권한이 필요합니다.
그런 다음 Consul Template 프로세스가 해당 경로를 통해 써야 합니다.
영향은 프로세스 권한과 렌더링된 콘텐츠에 크게 의존합니다.
실질적인 결과는 다음과 같습니다:
이것은 기본 설치에서의 원격 무인증 임의 쓰기가 아니었습니다.
그러나 권한이 있는 또는 공유 파일시스템 배포에서 의미 있는 영향을 미치는 명확한 로컬 신뢰 경계 실패였습니다.
HashiCorp는 이 문제를 다음과 같이 분류했습니다:
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N
공개된 기본 점수는 다음과 같습니다:
4.7 / Medium
해당 벡터는 다음을 반영합니다:
공식 공지에는 또한 리다이렉션된 쓰기가 기존 파일을 덮어쓸 수 있다고 명시적으로 문서화되어 있습니다.
점수가 중간 수준인 이유는 파일시스템 영향이 이론적이기 때문이 아니라 악용이 로컬 경로 제어 조건에 의존하기 때문입니다.
HashiCorp 공지에는 다음과 같이 나열되어 있습니다:
Affected: consul-template up to and including 0.42.0
Fixed: consul-template 0.42.1
수정 사항은 2026년 7월 8일 0.42.1 릴리스로 제공되었습니다.
0.42.1 패치는 여러 계층에서 쓰기 경로를 강화했습니다.
패치된 헬퍼는 os.Lstat()를 사용하여 다음을 검사합니다:
그리고 해당 구성 요소가 링크일 때 거부합니다.
이로써 보고서 및 회귀 테스트에서 다루는 직접 부모 리다이렉션 및 최종 파일 심볼릭 링크 사례가 차단됩니다.
지원되는 Unix 플랫폼에서 대상은 O_NOFOLLOW로 열립니다.
이로 인해 사전 검사와 열기 사이에 최종 구성 요소가 심볼릭 링크가 되면 열기 자체가 실패합니다.
사전 검사만으로는 또 다른 TOCTOU 창이 생길 수 있기 때문에 이것은 중요합니다.
플랫폼별 구현은 Windows에서는 no-op이며, Windows에서는 동일한 메커니즘으로 O_NOFOLLOW를 사용할 수 없습니다.
패치는 경로 기반 소유권 및 모드 작업을 디스크립터 기반 작업으로 교체했습니다:
f.Chown(uid, gid)
f.Chmod(perm)
이로써 메타데이터 변경이 나중에 경로를 다시 해석하는 대신 실제로 열린 파일에 바인딩됩니다.
헬퍼는 이제 stat 실패가 진정한 os.IsNotExist일 때만 부모 디렉터리를 생성합니다.
권한 실패와 같은 다른 오류는 쓰기 경로로 계속 진행하는 대신 반환됩니다.
패치는 다음에 대한 집중 테스트를 추가했습니다:
공개 패치 논의에는 중요한 한계가 명확히 문서화되어 있습니다.
새로운 검증은 다음을 확인합니다:
모든 상위 조상 구성 요소를 순회하며 거부하지는 않습니다.
메인테이너들은 writeToFile에 완전한 포함 검사를 고정할 구성된 샌드박스 루트가 없고, 일반적인 운영 체제가 macOS의 /var -> /private/var와 같은 합법적인 관리 링크를 경로 접두사에 포함할 수 있기 때문에 해당 경계를 선택했습니다.
O_NOFOLLOW도 모든 조상 디렉터리가 아닌 최종 구성 요소만 보호합니다.
이것은 보고된 취약점의 상태나 공식 수정 버전을 변경하지 않습니다.
다만 패치가 제공하는 정확한 보안 속성을 명확히 합니다:
이 구분은 기술 문서에서 보존할 가치가 있습니다.
저는 2026년 3월 21일에 이 문제를 두 번째 독립적인 Consul Template 발견으로 HashiCorp 보안 팀에 비공개로 보고했습니다.
보고서에는 다음이 포함되었습니다:
원래 후속 이메일은 메일링 리스트 스팸 필터에 걸린 것으로 보여 보안 팀의 보고 큐에 없었습니다.
제가 전체 보고서를 다시 전달한 후 HashiCorp는 엔지니어링 팀과 연결하여 첫 번째 Consul Template 문제와 별개로 조사했습니다.
HashiCorp는 0.42.1에서 취약점을 수정하고 2026년 7월 8일에 HCSEC-2026-20을 게시했습니다.
IBM은 동일한 CVE에 대해 해당 보안 공지를 게시했습니다.
두 공식 공지 모두 보고자를 다음과 같이 인정했습니다:
Mohamed Abdelaal (0xmrma)
핵심 교훈은 간단합니다:
경로 문자열은 그것이 가리키는 파일시스템 객체와 같은 것이 아닙니다
이 구분은 권한 있는 코드가 공격자의 영향을 받는 경로를 쓸 때마다 중요합니다.
문자열이 의도된 디렉터리로 시작하는지 확인하는 것만으로는 충분하지 않습니다.
탐색 시퀀스가 없는 깨끗한 경로라도 다음을 통해 다른 곳으로 해석될 수 있습니다:
민감한 작업은 올바른 경계에서 신원이 검증된 대상에 묶여 있어야 합니다.
이 문제는 또한 더 넓은 규칙을 강화합니다:
이미 열린 파일 디스크립터가 있다면 경로를 다시 해석하는 대신 해당 디스크립터를 통해 보안에 민감한 작업을 적용하십시오
이것이 바로 디스크립터 기반 Chown 및 Chmod 변경이 중요한 이유입니다.
writeToFile은 인증서 및 개인 키와 같은 민감한 자료용으로 문서화되어 있습니다os.Create 또는 os.OpenFile로 대상을 직접 열었습니다Chown 및 Chmod는 추가적인 변경 가능 경로 신뢰를 도입했습니다0.42.1은 링크 검사, 지원되는 곳의 O_NOFOLLOW, 디스크립터 기반 메타데이터 작업 및 회귀 테스트를 추가했습니다이 취약점은 ../ 탐색에 관한 것이 아니었습니다.
경로 문자열은 올바르게 보였습니다.
파일시스템 대상은 그렇지 않았습니다.
Consul Template은 운영자가 의도한 경로를 받아들이고, 공격자가 배치한 리다이렉션을 따라가며, 렌더링된 콘텐츠를 다른 파일에 썼습니다.
그것이 이 문제가 CVE-2026-14361이 된 이유입니다.
consul-template 0.42.1에서 수정되었습니다.