kritsana.devpassing
runartifactsdocsworkhistorydispatch

© 2026 Kritsana Prasit — built from source on a self-hosted runner

resume.pdfrssdispatch

back to artifacts
category: securitydate: 13 Nov 2026read: 3 min readsource: posts/lock-github-actions-supply-chain.mdx

Lock your GitHub Actions: กัน Supply-chain Attack ด้วย lockfile แทนการ pin SHA ไปมีอีกทาง

GitHub Actions รองรับ workflow lockfile แล้ว ใช้ gh actions-lock เก็บ commit SHA ไว้ในไฟล์ actions.lock แก้ปัญหา tag ที่ถูกแอบย้ายปลายทาง พร้อม zizmor v1.32.0 ที่รองรับ lockfile และ Renovate/Dependabot ที่อัปเดตให้อยู่

Lock your GitHub Actions: กัน Supply-chain Attack ด้วย lockfile แทนการ pin SHA ไปมีอีกทาง

ถ้าคุณเคยเจอกรณีที่ uses: some/action@v4 โดยไม่ได้ pin SHA คุณควรรู้ว่ามันเป็นช่องโหว่ที่เปิดทิ้งไว้เลย เพราะ tag ใน Git เป็น mutable — ใครมีสิทธิ์ push เข้า repo ก็ย้ายปลายทางของ tag นั้นได้ทันที แล้วทุก workflow ที่อ้าง tag นี้จะรันโค้ดของคนอื่นโดยไม่รู้ตัว

GitHub เพิ่งเปิดตัว workflow lockfiles แบบ GA (ประกาศ 28 ต.ค.) ซึ่งเปลี่ยนวิธีแก้ปัญหานี้ไปพอสมควร คือไม่ต้องมานั่ง hash SHA เองแล้ว แต่ให้เครื่องมือจัดการ

บทความ Lock your GitHub Actions โดย Hugo van Kemenade ลง 11 พ.ย. 2026


ปัญหาคืออะไร

ก่อนหน้านี้คำแนะนำมาตรฐานคือ pin ไปที่ full commit SHA แทน tag เช่น:

yaml
steps:
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
    with:
      persist-credentials: false
  - uses: j178/prek-action@44924fe9ef4a6f88253c4b6b1bf11c689d3ce53d # v3.1.0

วิธีนี้ป้องกัน supply-chain attack ได้ เพราะ SHA เปลี่ยนไม่ได้ แต่มีต้นทุนที่แสดงออกมาชัดเจน:

  • คนอ่าน workflow ไม่รู้ว่าใช้เวอร์ชันไหน ต้องไปหา SHA ใน GitHub เอง
  • อัปเดต dependency กลายเป็นงานยาก ต้องมานั่งหา SHA ใหม่เองทุกครั้ง
  • มันไม่ scale โปรเจกต์ที่มี workflow เยอะ ๆ จะดูแลไม่ไหว

Lockfile มาแก้ตรงนี้


วิธีใช้: สองคำสั่ง

ติดตั้ง gh-actions-lock extension ให้ gh CLI ก่อน:

console
$ gh extension install github/gh-actions-lock
✓ Installed extension github/gh-actions-lock

แล้วในโปรเจกต์รัน:

console
$ gh actions-lock
 
✓ All 1 workflows valid

เท่านั้นเอง ไฟล์ workflow จะเปลี่ยนจาก SHA เป็น tag:

diff
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
-      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+      - uses: actions/[email protected]
-      - uses: j178/prek-action@44924fe9ef4a6f88253c4b6b1bf11c689d3ce53d # v3.1.0
+      - uses: j178/[email protected]

แล้วจะได้ไฟล์ .github/workflows/actions.lock ที่เก็บ mapping ระหว่าง tag กับ SHA จริง:

yaml
# This file is machine-generated by `gh actions-lock`.
# Do not edit by hand; run `gh actions-lock` to update.
# Docs: https://gh.io/actions-lockfile
version: 'v0.0.3'
workflows:
  '.github/workflows/lint.yml':
    - 'actions/[email protected]'
    - 'j178/[email protected]'
dependencies:
  'actions/[email protected]':
    ref: 'v7.0.1'
    commit: 'sha1-3d3c42e5aac5ba805825da76410c181273ba90b1'
    owner_id: 44036562
    repo_id: 197814629
  'j178/[email protected]':
    ref: 'v3.1.0'
    commit: 'sha1-44924fe9ef4a6f88253c4b6b1bf11c689d3ce53d'
    owner_id: 10510431
    repo_id: 1052387486

ตอนนี้ทั้งสองอย่างอยู่ด้วยกัน: คนอ่านเห็น tag ที่เข้าใจง่าย และ ระบบมี SHA ที่ตรวจสอบได้


อัปเดต dependency แล้ว lockfile พังไหม

ไม่พัง — Renovate และ Dependabot รองรับ lockfile อยู่แล้ว การอัปเดตแบบ periodic จะอัปเดต lockfile ไปด้วย

แต่ Hugo เตือนเรื่องสำคัญในโพสต์: ใช้ cooldown ด้วย เพื่อไม่ให้การอัปเดตถี่เกินไปจนรับ patch ที่ยังไม่ผ่านการทดสอบ


อย่าลืม verify ใน CI

GitHub แนะนำให้ตรวจสอบ lockfile ใน CI ด้วย เพื่อกันกรณี lockfile หลุดจาก workflow หรือถูกแก้

วิธีที่ Hugo ใช้เองคือแยกเป็น job ต่างหากใน workflow เดิม ให้รันขนานกันได้ และใช้ runner เบากว่า:

yaml
# Fails when .github/workflows/actions.lock is out of sync with the
# workflows or a locked pin no longer verifies upstream.
lockfile:
  runs-on: ubuntu-slim
  env:
    GH_TOKEN: ${{ github.token }}
 
  steps:
    - uses: actions/[email protected]
      with:
        persist-credentials: false
    - run: gh extension install github/gh-actions-lock --pin v0.4.1
    - run: gh actions-lock --verify

ข้อควรระวัง: ถ้าเพิ่มไฟล์ workflow ใหม่ หรือแก้ workflow เดิม ต้องรัน gh actions-lock ใหม่ ไม่งั้น CI จะ fail ว่า lockfile ไม่ตรงกับ workflow


zizmor: ตัว linter ที่ควรมีคู่กัน

Hugo แนะนำ zizmor เป็น security linter สำหรับ GitHub Actions และบอกตรง ๆ ว่า "ถ้ายังไม่ใช้ แนะนำให้ใช้เลย"

จุดที่สำคัญคือ zizmor v1.32.0 เป็นเวอร์ชันแรกที่รองรับ lockfiles เพราะก่อนหน้านั้นมันจะบอกให้ hash-pin action ซึ่งขัดกับแนวทาง lockfile ใหม่

ใช้กับ pre-commit ได้:

yaml
- repo: https://github.com/zizmorcore/zizmor-pre-commit
  rev: v1.32.0
  hooks:
    - id: zizmor

ตัวอย่างจริงที่ใช้แล้ว

Hugo ยกตัวอย่างโปรเจกต์ Python หลายตัวที่ใช้แนวทางนี้แล้ว:

  • python-pillow/Pillow#10428
  • python/release-tools#477
  • python/miss-islington#758
  • python/cpython#161811

cpython เองก็ใช้ ซึ่งบอกได้ว่าแนวทางนี้ไม่ได้เป็นแค่เทคนิคสำหรับโปรเจกต์เล็ก


ถ้าจะทำในโปรเจกต์ตัวเอง

ลำดับที่ง่ายที่สุด:

bash
gh extension install github/gh-actions-lock
gh actions-lock
git add .github/workflows/actions.lock .github/workflows/
git commit -m "chore: lock GitHub Actions"

แล้วอย่าลืม:

  1. เพิ่ม job lockfile ที่รัน gh actions-lock --verify ใน CI
  2. เพิ่ม zizmor เข้า pre-commit hook (เวอร์ชัน v1.32.0 ขึ้นไป)
  3. ตั้ง cooldown ให้ Renovate/Dependabot อัปเดตแบบมีจังหวะ

ข้อดีคือทำครั้งเดียวแล้วทีมทั้งทีมได้ประโยชน์ เพราะ lockfile อยู่ใน repo ทุกคน pull มาได้เลย และคนที่เพิ่งเข้ามาทีมก็ได้ความปลอดภัยนี้ฟรี ๆ

contents

  • ปัญหาคืออะไร
  • วิธีใช้: สองคำสั่ง
  • อัปเดต dependency แล้ว lockfile พังไหม
  • อย่าลืม verify ใน CI
  • zizmor: ตัว linter ที่ควรมีคู่กัน
  • ตัวอย่างจริงที่ใช้แล้ว
  • ถ้าจะทำในโปรเจกต์ตัวเอง

related documents

security · 3
  • CVE-2026-119618: RCE ระดับ critical ใน Apache HTTP Server เจาะผ่าน mod_http2 ได้ยังไง และต้องแก้อะไร

    13 Nov 2026 · 3 min read

  • Security Best Practices for OpenClaw: Hardening Your Self-Hosted AI Agent

    06 Apr 2026 · 5 min read

  • Axios ถูกฝังมัลแวร์: บทเรียนด้านความปลอดภัยสำหรับนักพัฒนา

    06 Apr 2025 · 3 min read

comments