1 điểm bởi GN⁺ 2025-04-01 | 1 bình luận | Chia sẻ qua WhatsApp
  • Nếu tận dụng được khoảng thời gian hiệu lực rất ngắn của GITHUB_TOKEN bị lộ công khai, có thể mở ra một đường tấn công chuỗi cung ứng dẫn tới thực thi mã trong workflow GitHub Actions của nhiều kho dùng CodeQL
  • Token này nằm trong workflow artifact do workflow debug thất bại của kho github/codeql-action tải lên, và là token cài đặt GitHub App có quyền contents: write, actions: write, packages: write
  • Việc tấn công thành công hay không phụ thuộc vào race condition: phải tải và dùng token trước khi job kết thúc sau khi artifact được tải lên; theo log thực tế là khoảng 1.022 giây, và theo quan sát thì trong khoảng 2 giây có thể tạo branch, push poc.txt, và tạo tag thành công
  • Do cấu hình CodeQL mặc định nội bộ thực thi tag v3 của github/codeql-action, và tag này không phải là bất biến, nên nếu kẻ tấn công chuyển tag sang một commit độc hại thì cả các kho dùng workflow CodeQL mặc định cũng có thể bị ảnh hưởng
  • Khoảng 3 giờ sau khi nhận báo cáo, GitHub đã đưa ra PR để vô hiệu hóa việc tải lên debug artifact và gán CVE-2025-24362, đồng thời nêu trong advisory rằng không có bằng chứng về việc nền tảng hay hệ thống bị xâm phạm

Đường tấn công chuỗi cung ứng CodeQL bắt đầu từ artifact công khai

  • Chỉ một secret bị lộ công khai cũng có thể dẫn tới một tấn công chuỗi cung ứng tiềm tàng nhắm vào GitHub CodeQL
  • Secret này chỉ có hiệu lực khoảng 1.022 giây mỗi lần, nhưng trong khoảng đó kẻ tấn công vẫn có thể thực hiện các bước cần thiết để chạy mã bên trong workflow GitHub Actions
  • Phạm vi ảnh hưởng có thể chạm tới cả GitHub Cloud lẫn GitHub Enterprise
  • Các thiệt hại có thể xảy ra gồm:
    • Rò rỉ mã nguồn của các kho private sử dụng CodeQL
    • Đánh cắp GitHub Actions secrets trong job workflow CodeQL
    • Thực thi mã trong hạ tầng nội bộ nơi workflow CodeQL chạy
    • Đánh cắp secrets từ các workflow dùng GitHub Actions Cache trong các kho sử dụng CodeQL
  • Theo advisory của GitHub, công ty không tìm thấy bằng chứng cho thấy nền tảng hay hệ thống đã bị xâm phạm

Cách phát hiện secret

  • Một Actions Artifacts Secret Scanner đã được sử dụng: tải các GitHub Actions workflow artifact, giải nén đệ quy, rồi quét secret bằng Nosey Parker
  • Tính năng này đã được tích hợp vào Chariot và được mã nguồn mở dưới dạng tính năng Gato
  • Sau một ngày quét, token được phát hiện trong artifact của kho github/codeql-action
    • Artifact mục tiêu là file zip my-debug-artifacts do workflow “PR Check – Debug artifacts after failure” tải lên
    • Khi giải nén my-db-java-partial.zip bên trong, một GitHub Token bắt đầu bằng ghs_ đã được phát hiện trong crash report
    • Kiểm tra thủ công cho thấy đây là token cài đặt GitHub App được lưu trong một file chứa biến môi trường của GitHub Runner

Cấu trúc liên kết giữa GitHub Actions, artifact và CodeQL

  • GitHub Actions là một nền tảng CI/CD chạy các tác vụ được định nghĩa trong workflow YAML trên runner
  • Mỗi workflow run đều tạo ra GITHUB_TOKEN, là token cài đặt GitHub App được sinh tự động
    • Runner dùng token này để xác thực với GitHub và thực hiện các thao tác workflow yêu cầu
    • Quyền có thể được thiết lập ở cấp file workflow, kho hoặc tổ chức
  • GitHub Actions workflow artifact là các file mà workflow lưu vào GitHub Actions để dùng sau này
    • Mặc định, bất kỳ ai có quyền đọc kho đều có thể truy cập
    • Chúng được lưu tối đa 90 ngày
  • CodeQL là công cụ phân tích mã của GitHub, dùng để thực hiện phân tích tĩnh trên kho GitHub nhằm tìm lỗ hổng
  • Các công cụ bảo mật như CodeQL đôi khi cần truy cập vào hệ thống và dữ liệu nhạy cảm, nên nếu bị xâm phạm chúng có thể trở thành backdoor

Quyền của token và race condition

  • Ở bước “Setup Job” trong log workflow, GITHUB_TOKEN đó được xác nhận là có quyền ghi đầy đủ
  • Các quyền đặc biệt quan trọng gồm:
    • contents: write: có thể tạo branch, tạo tag, tải lên release artifact
    • actions: write: có thể kích hoạt Actions job và sự kiện workflow_dispatch
    • packages: write: có thể tải package lên
  • Vì token chỉ có hiệu lực trong lúc workflow job đang chạy, cuộc tấn công cần thỏa mãn ba điều kiện:
    • Token phải có quyền ghi
    • Phải dùng upload artifact API v4, cho phép lấy artifact trước khi job hoàn tất
    • Khoảng thời gian giữa lúc artifact được tải lên và lúc job kết thúc phải đủ để tải token, giải nén và sử dụng
  • CodeQL không dùng trực tiếp action actions/upload-artifact mà gọi thủ công upload artifact client trong mã nguồn, và theo comment trong mã thì đang dùng version 4
  • Theo log GitHub thô, khoảng thời gian này là cực ngắn:
    • “Finalizing artifact upload”: 17:22:09.888
    • “Cleaning up orphan processes”: 17:22:10.911
    • Tính ra là khoảng 1.022 giây; theo quan sát thì sau cleanup token còn hiệu lực thêm khoảng 1 giây, nên được xem là khoảng 2 giây

PoC: chạy artifact_racer.py

  • Một script Python để kiểm chứng có tên artifact_racer.py đã được viết
  • Luồng hoạt động như sau:
    • Liên tục truy vấn xem workflow “PR Check – Debug artifacts after failure” có khởi chạy trong kho github/codeql-action hay không
    • Theo dõi artifact của workflow đang chạy
    • Khi artifact xuất hiện, tải xuống và trích xuất GITHUB_TOKEN
    • Dùng token đã trích xuất để tạo branch mới
    • Push một file rỗng tên poc.txt lên branch đó
    • Tạo một tag mới cho commit đó
  • Do artifact có kích thước khoảng 21MB, người nghiên cứu cho rằng vẫn có thể thành công trong giới hạn thời gian này
  • Sau khi thành công trên kho thử nghiệm, script được chạy với kho github/codeql-action
  • Khoảng 2 giờ sau workflow được kích hoạt, script đã lấy được token và tạo branch, push file, tạo tag thành công

Việc thao túng tag đã làm tăng phạm vi ảnh hưởng

  • Kẻ tấn công có thể dùng token này để thêm mã độc vào các branch không được bảo vệ
  • Tinh vi hơn, chúng cũng có thể chèn một thay đổi độc hại nhỏ vào branch tính năng trước khi merge rồi chờ merge xảy ra
  • Quyền tạo tag cũng đặc biệt quan trọng
    • Nếu gắn tag v3 vào một commit có mã độc, những người dùng gọi thủ công codeql-action@v3 có thể sẽ chạy mã độc đó
  • Ảnh hưởng lớn hơn đến từ cấu hình CodeQL mặc định
    • Khi bật CodeQL trong thiết lập mặc định của kho, một workflow GitHub Actions đặc biệt sẽ chạy dù không hiển thị trong danh sách workflow của kho
    • Workflow này thực hiện checkout kho, khởi tạo CodeQL, quét CodeQL và tải kết quả lên
    • Nội bộ, nó chạy action từ kho github/codeql-action tại commit mà tag v3 đang trỏ tới
  • Ở thời điểm đó, tag v3 không phải bất biến và cũng không dùng workflow pinning như GitHub khuyến nghị
  • Nếu kẻ tấn công dùng GITHUB_TOKEN đã bị xâm phạm để chuyển v3 sang một commit độc hại, các kho dùng workflow CodeQL mặc định có thể chạy CodeQL action độc hại
  • Vì CodeQL action sẽ checkout mã nguồn của kho đích, action độc hại có thể làm rò rỉ mã nguồn từ các kho dùng cấu hình CodeQL mặc định

Đường cache poisoning của GitHub Actions Cache

  • GITHUB_TOKEN của CodeQL action mặc định chỉ có quyền đọc, nên chỉ với cấu hình mặc định thì chưa thể trực tiếp ghi vào kho, cài backdoor qua release, hay đánh cắp secrets thông qua workflow_dispatch
  • Thay vào đó, CodeQL action mặc định chạy trên branch main của kho
  • Branch main của kho GitHub có thể ghi cache entry dùng chung cho toàn bộ kho, tạo cơ hội cho GitHub Actions cache poisoning
  • GitHub Actions Cache Poisoning là kỹ thuật được mô tả trong bài viết của Adnan Khan, còn Cacheract là malware duy trì chỗ đứng trong build pipeline thông qua cache poisoning
  • Nếu kẻ tấn công triển khai Cacheract trong workflow CodeQL, có thể xảy ra chuỗi sau:
    • Dự đoán cache entry
    • Ghi đè entry đó bằng action độc hại
    • Giành được thực thi mã trong workflow dùng actions/cache
    • Đánh cắp GitHub Actions secrets và GITHUB_TOKEN có quyền cao của workflow đó
  • Ngay cả khi CodeQL action độc hại bị phát hiện và lỗ hổng được khắc phục, Cacheract vẫn có thể tiếp tục cache poisoning
  • Các ví dụ repo lớn được xác nhận dùng cả CodeQL lẫn actions/cache gồm Homebrew, Angular, Grafana

CVE-2025-24362 và bản vá

  • Kết quả của công bố này là CVE-2025-24362 đã được gán
  • GITHUB_TOKEN bị lộ công khai nằm trong debug artifact do CodeQL Action tải lên sau một workflow code scanning thất bại
  • Kho CodeQL Actions đã cố tình tạo lỗi để kiểm thử, nhưng nếu những người dùng CodeQL Actions khác cũng gặp lỗi tương tự, secrets của chính họ cũng có thể đã bị lộ qua biến môi trường của workflow
  • Vấn đề này đã được sửa trong CodeQL Action 3.28.3
  • Tác động tiềm tàng lớn nhất không nằm ở chính CVE, mà ở con đường khai thác lỗ hổng trên kho CodeQL Actions để thực hiện tấn công chuỗi cung ứng nhắm vào người dùng CodeQL

Ứng phó của GitHub và các biện pháp giảm thiểu được khuyến nghị

  • Mốc thời gian phản ứng của GitHub như sau:
    • 15:13 UTC ngày 22/01/2025: gửi báo cáo cho GitHub
    • 17:48 UTC ngày 22/01/2025: GitHub xác nhận đã tiếp nhận
    • 18:28 UTC ngày 22/01/2025: GitHub xác nhận lỗ hổng và tạm thời vô hiệu hóa workflow “PR Check – Debug artifacts after failure”, đồng thời gửi PR để vô hiệu hóa việc tải lên debug artifact
    • 24/01/2025: GitHub gán CVE-2025-24362 và công bố security advisory
  • Các biện pháp để giảm rủi ro lộ secret qua GitHub Actions workflow artifact gồm:
    • Chỉ tải lên các file hoặc thư mục cụ thể dưới dạng workflow artifact
    • Tránh tải lên artifact có chứa biến môi trường, .git/config, hoặc các file trong thư mục <path_to_runner_dir>/_work/_temp/ của runner
    • Giới hạn quyền của GITHUB_TOKEN ở chế độ chỉ đọc
    • Thực hiện quét secret trước khi tải artifact lên

1 bình luận

 
GN⁺ 2025-04-01
Ý kiến trên Hacker News
  • Nếu GitHub thúc đẩy immutable actions sớm hơn, tác động kiểu này hẳn đã nhỏ hơn nhiều
    Tôi cứ phải nhắc đi nhắc lại rằng tính năng này có thể chặn hơn 70% bề mặt tấn công hiện nay của GitHub Actions. Nhìn cảnh tuần nào cũng có sự cố, tôi nghĩ đã đến lúc nên phát hành rồi
    [1] https://github.com/features/preview/immutable-actions

    • Nếu nó vẫn ở trạng thái preview thì rất có thể là có lý do. Có thể có lỗi nghiêm trọng, lỗ hổng bảo mật, hoặc phá vỡ tương thích mà nếu vội vàng sẽ gây thiệt hại lớn hơn
  • Không có lời giải thích vì sao token tạm thời này lại có cả quyền tạo bản triển khai mới và tạo chứng thực artifact
    Họ nói bản sửa là tắt debug log, nhưng không trả lời liệu họ có điều chỉnh quyền của token tạm thời cho phù hợp hơn với engine phân tích mã hay không

    • Nghe như câu chuyện cũ ai cũng biết. Kỹ sư đang xây dựng gặp lỗi bị từ chối quyền, thế là cấp mọi quyền, rồi sau đó không quay lại giảm xuống theo nguyên tắc đặc quyền tối thiểu
    • Nếu token tạm thời của GitHub Actions không có phạm vi quyền được định nghĩa trong workflow, nó sẽ áp dụng phạm vi mặc định rộng rãi hoặc hạn chế tùy theo thiết lập của repository. Thiết lập này cũng có thể được cấu hình ở cấp tổ chức để hạn chế tất cả repository
      Trước đây, mặc định chỉ là cấu hình rộng rãi, nên đáng tiếc là nhiều tổ chức và repository cũ vẫn dùng thiết lập này
      Khi tạo repository mới, nó kế thừa mặc định từ tổ chức cha, nên nếu không ai thay đổi thì mặc định không an toàn này vẫn còn. Không có thiết lập toàn cục cho người dùng, nên repository mới thuộc sở hữu cá nhân dùng mặc định hạn chế. Theo tôi biết, tổ chức mới tạo cũng dùng mặc định tốt hơn
      [0]: https://docs.github.com/en/actions/security-for-github-actio...
    • Token tạm thời của Actions mặc định có toàn quyền ghi. Muốn dùng phiên bản chỉ đọc thì phải chọn rõ ràng

      Read and write permissions
      Workflows have read and write permissions in the repository for all scopes.
      Chỉ đọc dòng này trong tài liệu (https://docs.github.com/en/actions/security-for-github-actio...) thì có thể nghĩ khác
      If the default permissions for the GITHUB_TOKEN are restrictive, you may have to elevate the permissions to allow some actions and commands to run successfully.
      Nhưng trong tổ chức GitHub của chúng tôi, "Read and write permissions" là mặc định, nên có thể xác nhận rằng câu trong tài liệu đó không hợp lý

    • Vụ Microsoft bị hack năm 2023 cũng tương tự. Đó là sự cố mà CISA đã công khai chỉ trích bảo mật quá tệ, nhưng ngay cả bài blog Microsoft đăng để giải thích sự cố cũng còn quá nhiều câu hỏi chưa được trả lời
    • Hy vọng việc tắt debug log chỉ là biện pháp tạm thời nhanh. Nó không nên là bản sửa cuối cùng
  • Tôi ngày càng tin chắc rằng CI và CD phải là hai môi trường hoàn toàn tách biệt. CI bị xâm phạm không được phép dẫn đến rò rỉ token liên quan đến CD

    • Cá nhân tôi rất quan tâm đến lĩnh vực này, và tôi nghĩ lời giải không phải là tách CD thành một hệ thống nhỏ, chuyên biệt riêng, mà là làm cho CD giống như đa yếu tố hơn
      Ví dụ, bắt buộc phải thỏa điều kiện như "sub":"repo:octo-org/octo-repo:environment:prod"[1], và nếu muốn làm hệ thống chắc chắn hơn nữa thì có thể thêm các [fun claims][] khác
      1: https://docs.github.com/en/actions/security-for-github-actio...
      fun claims: https://github.com/github/actions-oidc-debugger#readme
    • Về bản chất, đây là cách tách biệt nhiệm vụ và mối quan tâm thể hiện ra. Một số dự án tốt cũng vận hành theo cách này. Kỹ thuật, công cụ cụ thể, ranh giới giữa CI và CD sẽ khác nhau tùy theo tính chất của sản phẩm cuối cùng, nhưng về mặt khái niệm thì hoàn toàn đúng
  • Thời gian phản hồi không đùa được đâu. Cách GitHub phản ứng khá ấn tượng

    • Việc một token công khai có toàn quyền ghi bị lộ thì không ấn tượng cho lắm
  • Với tư cách là người mang họ Prater, vì cái tên này bắt nguồn từ Praetorian nên tôi thật sự ước gì mình sở hữu praetorian.com

    • Muốn vậy thì lẽ ra phải nghĩ ra trước khi phim “The Net” năm 1995 ra mắt
    • Dự án gokart của họ rất tuyệt
  • Dùng GitHub Actions công khai là tự chuốc lấy rắc rối, nhất là nếu không phân tích quy trình workflow
    Thà tự host woodpecker hoặc các CI builder tốt khác như circle, travis, gitlab, v.v. còn hơn

  • Tôi đã áp dụng CodeQL cho PR của OpenZFS. Việc này không phải là vấn đề với OpenZFS, vì mã của chúng tôi không phải bí mật :)

    • Dù mã không phải bí mật thì tôi vẫn không nghĩ đó là phán đoán tốt. Vì kẻ tấn công có thể thêm bất cứ thứ gì vào mã hoặc artifact phát hành
      Dù sao thì ít nhất cũng may là đã được xử lý nhanh
  • Cái này đã được sửa chưa?

    • Như trong bài viết và các bình luận ở đây đã nói, rồi. Sau khi được báo cáo vào tháng 1, GitHub đã giảm thiểu trong vòng 3 giờ
  • Trang này hiệu năng tệ đến mức tôi gần như không cuộn được