CVE-2026-48168

CVE-2026-48168

Area
AI Agent / CI/CD
Credit
Public Attribution
Credit Note
CVSS
10
CVSS Source
CNA / Vendor
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
CWE
CWE-862
Doc QA
Reviewed
Evidence Level
Dynamic Isolated
Evidence Ref
772f151c2a4804bea59fbfc8d9b536816c60de48
Fixed
Fixed Version
>= 4.6.40
Impact
Code Execution
Key Finding
외부 PR branch 이름이 privileged workflow의 shell 명령에 인용 없이 삽입돼 command injection으로 이어졌습니다.
Published
Aug 5, 2026
Released
Reported
Reviewed At
Sep 4, 2026
Role
Discovery
Root Cause
PoC
Dynamic Validation
Disclosure
Fix Review
Evidence Curation
Score Note
Severity
Critical
Status
Public
Target
PraisonAI · Claude GitHub Actions workflow
Template Version
v2

01 Summary

🔎
정적 분석에서 PraisonAI의 issue-comment workflow가 외부 fork branch name을 unquoted shell command에 직접 보간함을 확인했습니다. 별도의 foxirain/langflow low-privilege canary workflow에서 non-collaborator의 @claude comment로 같은 sink를 재현해 Bash command execution과 $GITHUB_PATH 상태 변경을 관찰했습니다. PraisonAI production workflow 자체에서 payload를 실행하거나 credential에 접근하지는 않았습니다.
구분
확인 내용
Component
PraisonAI GitHub Actions issue-comment workflow
Attack Input
shell metacharacter가 포함된 external fork branch name
Preconditions
untrusted actor가 대상 PR에서 workflow trigger comment를 만들 수 있어야 함
Sink
pr.data.head.refgit fetch ...:${{ pr_branch }} shell command에 직접 보간
Verified
Bash injection으로 /tmp/p0canary 생성 및 $GITHUB_PATH 변조
Impact
동적 확인: low-privilege canary의 shell execution·다음 step PATH 영향 / 정적 확인: target workflow의 후속 privileged context 노출 가능성
Fix Principle
trusted-actor gate, branch 값을 env로 전달·quote, fixed local ref와 least privilege 사용
목차 · 섹션으로 이동

Attack Chain

검증 결론: non-collaborator가 제어한 branch metadata가 low-privilege canary job의 Bash에서 해석되어 canary path와 $GITHUB_PATH가 바뀌고, 다음 canary step의 gh resolution에 영향을 준 사실을 동적으로 확인했습니다. PraisonAI target job의 write 권한, id-token: write, GitHub App token을 소비하는 후속 Claude step은 workflow 정적 분석으로 확인했으며, privileged credential의 실제 사용·노출은 시험하지 않았습니다.

Disclosure Timeline

Date
Event
Evidence
기존 기록 없음
Reported
DB Reported 및 본문에 날짜 기록 없음
기존 기록 없음
Fixed
본문에는 fixed version만 있고 날짜 기록 없음
기존 기록 없음
Released
DB Released 및 본문에 날짜 기록 없음
2026-08-05
Published
DB Published 및 본문 공개일

02 Vulnerability

취약점 개요

PraisonAI의 .github/workflows/claude.yml은 issue comment에 @claude가 들어오면 PR branch를 fetch한 뒤 GitHub App token을 사용하는 작업을 수행했습니다. fork의 branch 이름은 외부 contributor가 정할 수 있지만 Bash run: block 안에 quoting 없이 들어갔습니다. 이 target 구조는 정적 분석으로 확인했습니다.
별도의 foxirain/langflow controlled run에서는 shell metacharacter가 포함된 branch 이름으로 PR을 만들고 댓글을 달자 Bash가 첫 git fetch ...:poc 뒤의 주입 command를 실행했습니다. 무해한 canary 파일을 만들고 $GITHUB_PATH 앞에 controlled directory를 추가해 다음 low-privilege canary step의 gh 해석이 바뀌는 것까지 확인했습니다.
공격자가 제어하는 값
fork PR의 branch name과 issue comment
취약 sink
Bash run: block의 unquoted git fetch ...:<branch>
Trigger 문제
댓글 작성자의 신뢰 여부 검사 없음
후속 권한
후속 Claude step에 GitHub App token·OAuth token 전달, job에 id-token: write 선언; 실제 credential·OIDC 사용은 미검증

03 Approach

조사 대상

CI workflow에서는 ${{ }} 표현식이 shell script로 들어가는 위치를 모두 찾고, 값의 출처가 trusted repository인지 fork metadata인지 구분했습니다. YAML상 문자열이라는 사실은 Bash에서 안전한 인자가 된다는 뜻이 아닙니다.
또한 injection step 자체의 기본 token만 보지 않고 뒤에 실행되는 credential-bearing steps를 확인했습니다. $GITHUB_PATH와 workspace는 step 사이에 상태를 전달하므로 초기 무권한 step이 후속 도구 해석에 영향을 줄 수 있었습니다.
외부 contributor가 만든 branch name이 실제 runner의 shell 문법으로 해석되고, 그 영향이 privileged 후속 step까지 지속되는가?

04 Root Cause

원인 분석

취약 명령은 git fetch origin pull/<number>/head:${{ steps.check_fork.outputs.pr_branch }} 형태였습니다. branch name이 shell word 안에 그대로 붙었지만 quote가 없어 command separator와 redirection 같은 metacharacter가 Bash 문법이 됐습니다.
workflow trigger는 @claude 문자열을 확인했지만 commenter가 collaborator인지 확인하지 않았습니다. 따라서 branch를 만든 outside contributor가 자신의 PR에 댓글을 달아 취약 job을 시작할 수 있었습니다. PraisonAI target source에는 write job permissions와 id-token: write가 선언돼 있었고, 후속 Claude step은 GitHub App token과 OAuth token을 전달받았습니다. 이 credential의 실제 사용·노출은 시험하지 않았습니다.
claude.yml · branch metadata가 shell source가 된 지점
run: | git fetch origin \ pull/${{ github.event.issue.number }}/head:\ ${{ steps.check_fork.outputs.pr_branch }} # expected data: branch name # actual interpreter: Bash source text
입력에서 영향까지의 경로
  1. 외부 contributor가 shell metacharacter가 든 fork branch를 만듭니다.
  1. 그 branch로 PR을 열고 @claude 댓글을 답니다.
  1. workflow가 신뢰 actor 검사 없이 시작됩니다.
  1. branch name이 unquoted Bash command에 삽입됩니다.
  1. controlled run에서는 canary와 $GITHUB_PATH 변경이 다음 low-privilege canary step에 남았습니다. 별도로 PraisonAI source에서 같은 상태 전달 경로 뒤에 credential-bearing Claude step이 있음을 확인했습니다.

05 Reproduction & Validation

재현 및 검증

foxirain/langflow의 통제된 read-only GitHub Actions run에서 외부 fork branch를 사용했습니다. payload는 secret을 읽거나 repository를 수정하지 않고 /tmp/p0canary 생성과 controlled directory를 $GITHUB_PATH에 추가하는 동작으로 제한했습니다. 이 run은 PraisonAI production workflow가 아닙니다.
다음 low-privilege canary step에서 command -v gh/tmp/p0canary/gh를 가리키는지 확인했습니다. 이 동적 결과와 PraisonAI target source의 credential-bearing 후속 step을 분리해 분석함으로써, privileged credential을 실제로 사용하지 않고 잠재적 영향 경로를 확인했습니다.
# outside fork branch name contains shell metacharacters # comment: @claude # observe controlled run 25624510066 and canary path
검사
입력·조건
관찰
의미
외부 Trigger
outside contributor의 @claude
job 시작
trusted actor gate 없음
Canary
branch name payload
/tmp/p0canary 생성
Bash command injection
Step 지속성
$GITHUB_PATH 변경
다음 step의 gh 경로 변경
후속 단계 영향
비파괴 범위
token/secret 접근 안 함
외부 반출 없음
검증 payload 제한
실제 controlled workflow run의 핵심 관찰
run id: 25624510066 trigger actor: outside contributor branch-derived shell payload: executed canary: /tmp/p0canary created next step command resolution: gh=/tmp/p0canary/gh secrets exfiltrated: no

06 Impact & Fix

영향과 수정

Controlled canary는 외부 contributor가 제어한 branch name으로 임의 shell syntax를 실행하고, $GITHUB_PATH를 통해 다음 low-privilege canary step의 gh resolution을 바꿀 수 있음을 확인했습니다. PraisonAI target job에는 GitHub App token을 사용하는 후속 Claude step과 id-token: write 선언이 있어 동일한 상태 조작이 privileged context에 영향을 줄 잠재적 chain이 존재했습니다. 다만 App token의 사용·탈취, OIDC token 발급, repository mutation은 재현하지 않았으므로 실제 영향은 credential availability, token scope, 후속 action·command 동작에 조건부입니다.
확인한 범위
  • controlled low-privilege GitHub Actions run의 shell command execution
  • outside contributor의 self-trigger
  • $GITHUB_PATH를 통한 다음 step 영향
제외한 범위
  • secret 값의 출력·외부 전송
  • 실제 repository 변조
  • LLM prompt injection
수정
PraisonAI 4.6.40에는 PR branch 값을 PR_BRANCH 환경변수로 전달하고 "${PR_BRANCH}"로 quote하는 수정이 적용되어 branch-name command injection이 차단되었습니다. Trusted-actor gate, 고정된 pr-${PR_NUMBER} local ref, job token·OIDC 권한 최소화는 추가 권고사항이며 4.6.40에는 적용되지 않았습니다.

07 Turning Points

Key Turning Points

🧭
핵심 변화는 AI prompt 문제로 보던 초기 해석을 deterministic shell injection으로 교정하고, 비파괴 canary와 권한 경계를 분리한 것입니다.
Stage
Prior Belief
New Evidence
Revised Judgment
Trigger
1. Vulnerability class
Claude workflow이므로 prompt injection일 수 있다고 보았습니다.
Branch name은 LLM 호출 전에 Bash source text로 해석됐습니다.
LLM 판단과 무관한 deterministic command injection으로 분류했습니다.
Bash sink가 모델 호출보다 먼저 실행된다는 확인이 계기였습니다.
2. Proof boundary
Secret 탈취나 repository write가 더 강한 증거가 될 수 있었습니다.
Canary file과 PATH shadowing만으로 shell execution과 다음 step 영향을 확인했습니다.
Credential을 읽지 않고 비파괴 side effect에서 실험을 중단했습니다.
Controlled run의 안전한 검증 경계를 정한 것이 계기였습니다.
3. Privilege boundary
Injection step의 권한만 보면 영향이 low privilege로 끝난다고 볼 수 있었습니다.
$GITHUB_PATH 상태가 다음 step에 남았고 target source에는 credential-bearing Claude step과 id-token: write가 있었습니다.
Low-privilege 동적 증거와 target privileged context의 정적 가능성을 분리했습니다.
Step 간 상태 지속성 확인이 계기였습니다.
4. Fix scope
Branch quoting만으로 workflow 보안 문제가 모두 해결된다고 볼 수 있었습니다.
Quote는 shell injection을 막지만 untrusted actor trigger와 넓은 job 권한은 별도 문제로 남았습니다.
Quoting fix와 actor authorization·least privilege 권고를 분리했습니다.
수정 범위를 다시 검토한 것이 계기였습니다.

Investigation Log

전체 판단 변화 원문
판단 변화
Prompt Injection
처음에는 Claude가 포함된 workflow라 prompt injection으로 볼 여지가 있었습니다. 그러나 취약 동작은 모델 호출 전에 Bash가 branch 이름을 해석하면서 발생했습니다. LLM 판단과 무관한 deterministic command injection으로 분류했습니다.
Secret 탈취
실제 runner에서 검증하더라도 secret 출력이나 repository write는 필요하지 않았습니다. canary와 PATH shadowing만으로 arbitrary shell execution과 다음 step에 대한 영향이 입증돼 공격을 그 선에서 중단했습니다.
현재 Step 권한
controlled run의 주입 step은 read-only 권한이었습니다. 여기서는 $GITHUB_PATH와 파일이 다음 canary step까지 지속되는 사실을 동적으로 확인했습니다. 별도로 PraisonAI target source에는 GitHub App token과 OAuth token을 전달받는 후속 Claude step 및 id-token: write 선언이 있었습니다. OIDC token 발급이나 credential 사용은 재현하지 않았으며, workflow를 job 전체의 잠재적 상태 흐름으로 평가했습니다.
Trigger와 Quote
branch 값을 quote하는 수정만으로 shell injection은 막을 수 있지만 누구나 privileged AI job을 시작하는 문제는 남습니다. 최종 방어 조건에 actor authorization과 최소 권한을 함께 포함했습니다.

Role & Credit

  • Portfolio author: Taegu Ha
  • Credit: Public Attribution
  • Credit Note: 기존 기록 없음
  • 검증은 PraisonAI target source의 정적 분석과 별도 controlled low-privilege canary run으로 구분했습니다.

08 Provenance

🗄️
322da5d0e45b3e13e6487c4a8c9eb04124233f56 링크는 current main에서 삭제된 감사·보존 파일의 historical snapshot입니다. 그 밖의 current artifact 링크는 main을 유지합니다.

분석 기준과 증거 보존

항목
최종 감사 결과
소스 기준
PraisonAI checkout 4985415e61043a1734903f6a6e8ca85efdaede7c
원본 검증
external fork branch metadata, workflow interpolation, canary file·GITHUB_PATH side effect를 연결
GitHub 보존 상태
Historical audit commit 64c54ec 당시 evidence 5개와 root manifest.json에 size·SHA-256을 고정했습니다. 현재 main은 evidence 4개이며 root manifest.json은 제거됐습니다.
무결성
사례별 SHA256SUMS 검증 통과, root manifest의 모든 file hash와 실제 파일 일치, README 상대 링크 확인 완료
보존 경계·제약
controlled run의 gh run view --log 텍스트 캡처는 보존; PraisonAI production credential·실제 secret·GitHub 원본 log ZIP·raw Codex session은 제외
감사 완료
2026-08-30 · controlled run log 추가, source/provenance와 전체 manifest 재검증 후 GitHub push 완료
이전 Summary 상세 · 원문 보존
외부 fork의 branch 이름이 따옴표 없이 git fetch 명령에 삽입됐고 누구나 @claude 댓글로 job을 시작할 수 있었습니다. 통제된 foxirain/langflow read-only canary run에서 shell execution과 $GITHUB_PATH 영향을 동적으로 확인했습니다. PraisonAI의 privileged workflow는 source snapshot으로 별도 분석했으며 target credential 접근이나 production 실행은 하지 않았습니다.
Taegu Ha · PraisonAI · CWE-862 · CVSS 10.0
2026년 8월 5일 공개 · PraisonAI 4.6.40에서 수정 · 공식 기록
구분
확인 내용
프로젝트·컴포넌트
PraisonAI GitHub Actions issue-comment workflow
공격 입력
shell metacharacter가 포함된 external fork branch name
필요 조건
untrusted actor가 대상 PR에서 workflow trigger comment를 만들 수 있어야 함
취약 지점
pr.data.head.refgit fetch ...:${{ pr_branch }} shell command에 직접 보간
검증 결과
Bash injection으로 /tmp/p0canary 생성 및 $GITHUB_PATH 변조
영향
동적 확인: low-privilege canary의 shell execution·다음 step PATH 영향 / 정적 확인: target workflow의 후속 privileged context 노출 가능성
수정 원칙
trusted-actor gate, branch 값을 env로 전달·quote, fixed local ref와 least privilege 사용

09 Artifacts

관련 파일

2026-08-30 증거 보강 감사
공개 advisory·CVE 레코드와 함께 취약 workflow snapshot 및 controlled run 25624510066의 169줄 gh run view --log 텍스트 캡처를 독립 보존했습니다. 이 캡처는 PraisonAI production log나 GitHub 원본 log ZIP이 아니며, secret 값은 검증에서도 수집하지 않았습니다.
  • p0-claude-canary-25624510066.logfoxirain/langflow read-only run의 전체 gh run view --log 텍스트 캡처; shell injection과 다음 step PATH persistence를 직접 기록

10 References

11 Takeaways

느낀 점

CI에서 metadata는 단순 데이터가 아니라 여러 interpreter를 차례로 통과하는 입력이었습니다. GitHub expression이 YAML을 지나 Bash source가 되는 경계를 그리자 취약점이 명확해졌습니다.
또 하나 남은 기준은 step 단위 권한만 보지 않는 것입니다. 파일과 environment file이 다음 step으로 이어지면 앞 단계의 작은 injection이 뒤 단계의 큰 권한을 빌릴 수 있습니다. 실제 피해를 만들지 않고도 이 연결을 canary로 보여줄 수 있었습니다.