Bỏ qua điều hướng

Công khaiDeep dive

Guardrail trong Claude Code và AgentKit (2/2): từng lớp chặn, chỗ hở và cách dùng

Phần 2/2: mổ từng lớp chặn của AgentKit, từ scout-block, privacy-block, simplify-gate tới hard-gate và guard skill, kèm các chỗ hở đã biết, thói quen nên giữ và bảng thuật ngữ.

12 phút đọc · v1.0.0 · Cập nhật 09/06/2026

EN · Guardrails in Claude Code and AgentKit (2/2): each guard layer, its gaps and good habits · Đọc bản tiếng Anh

Tóm tắt nhanh: mỗi lớp guardrail của AgentKit chặn một loại rủi ro khác nhau. Hook như scout-block và privacy-block chặn tool call bằng code; hard-gate và quy tắc chỉ là lời dặn; guard skill chỉ chạy khi bạn gọi. Biết lớp nào đang chạy thật mới kiểm đúng chỗ.

Phần 1 giải thích cơ chế hook trong Claude Code, bảy nhóm guardrail và các lớp settings. Phần này đi qua từng lớp một, rồi tới các chỗ hở và thói quen nên giữ. Cấu hình trong bài là ảnh chụp claudekit-engineer@2.19.1 (tháng 6/2026), đã đối chiếu lại với AgentKit 3.0.0-beta.1 như ghi chú ở Phần 1.

Công khai: mình là maintainer của AgentKit và có quan hệ affiliate: link AgentKit cuối bài là link affiliate.

Ghi chú: bản beta hiện tại của AgentKit (từ 3.0.0-beta.35, 21/10/2026) đã đổi format tên skill từ ak:<tên> sang ak-<tên>, nên lệnh trong bài đã cập nhật theo tên mới: Claude Code gõ /ak-plan, Codex gõ $ak-plan. Nếu bạn còn dùng bản cũ hơn, đổi ak- thành ak: là ra lệnh tương ứng.

Ba cột: hook chặn bằng code (scout-block, privacy-block, simplify-gate, workflow-artifact-gate), lời dặn trong ngữ cảnh (HARD-GATE, dev-rules-reminder) và guard skill chạy khi bạn gọi, mỗi lớp kèm chỗ hở của nó
Lớp nào chặn bằng code, lớp nào chỉ là lời dặn, lớp nào chỉ chạy khi bạn gọi.

scout-block: chặn đọc thư mục rác

Agent hay đọc node_modules/, chạy glob **/*.ts ở thư mục gốc (glob là mẫu khớp đường dẫn; **/*.ts nghĩa là mọi file .ts ở mọi thư mục con), hoặc cat dist/index.js. Mỗi lần như vậy là vài chục nghìn token bị nhét vào ngữ cảnh, kéo chi phí lên và chất lượng các lượt sau xuống. scout-block.cjs đăng ký ở PreToolUse, chạy trước mọi Read, Bash, Glob, Grep.

text
# Baseline .ckignore, do pattern-matcher.cjs xử lý
node_modules
dist
build
.next
.nuxt
__pycache__
.venv
venv
vendor
target
.git
coverage

Một ngoại lệ quan trọng: các lệnh build được cho qua. Những lệnh như npm build, go build, make, docker build vẫn chạy, kể cả khi quá trình build chạm vào node_modules hay dist. Nếu chặn cả nhóm này, các luồng phát hành và test của AgentKit dễ tự vấp ngay ở bước build.

Chỗ hở 1, khi hook crash: lỗi đọc dữ liệu (parse error) đều dẫn tới exit 0, tool được cho qua. Hook có lỗi thì lớp chặn đó tắt âm thầm.

privacy-block: chặn secret, bắt người dùng duyệt rõ ràng

Khi agent đụng vào .env, id_rsa, *.pem, credentials.yaml là secret lộ vào bản ghi hội thoại. Một khi đã vào ngữ cảnh, nó có thể bị ghi log, bị trích lại trong kết quả của agent duyệt, hoặc bị dán vào PR.

text
@@PRIVACY_PROMPT_START@@
{ "type": "PRIVACY_PROMPT", "question": {...}, "options": [...] }
@@PRIVACY_PROMPT_END@@

Claude đọc khối JSON này rồi gọi AskUserQuestion. Nếu người dùng đồng ý, thông báo của hook hướng dẫn đọc file theo đường đã được duyệt, ví dụ cat ".env" sau khi đã hỏi; code cũng hỗ trợ tiền tố APPROVED:. Điểm chính: phải có phê duyệt rõ ràng, không để model tự suy ra là người dùng đã đồng ý.

Chỗ hở 2, ngoại lệ cho Bash: privacy-block cho Bash đi qua và chỉ cảnh báo. Ai có quyền chạy Bash đều đọc được secret mà không qua bước phê duyệt.

Nếu secret đã lộ: privacy-block chỉ chặn việc đọc. Hãy đổi thông tin đăng nhập ngay, rà lại log hội thoại, rồi kiểm lịch sử git xem secret có bị commit không.

simplify-gate: chặn phát hành khi diff phình quá phạm vi

Một việc nhỏ có thể phình thành một PR đụng quá nhiều file: sửa phần kiểm tra đầu vào, thêm dọn dẹp, đổi định dạng, chỉnh vài hàm phụ bên cạnh. Khi bạn gõ kiểu "OK ship", simplify-gate.cjs (đăng ký ở UserPromptSubmit) đọc git diff HEAD rồi chỉ xét khi prompt có một trong các từ ship, merge, pr, deploy, publish.

Ngưỡng mặc định trong simplify.threshold ở bản này có ba con số:

  • Tổng số dòng thêm và xoá trong diff vượt 400.
  • Số file bị đụng vượt 8.
  • Số dòng thêm trong một file vượt 200.

Gate chỉ chặn khi simplify.gate.enabled=true. Các ngưỡng này có thể ghi đè trong .ck.json.

Chỗ hở 3, mặc định dễ hiểu nhầm: hooks.simplify-gate = true chỉ cho Claude Code gọi script. Muốn script thật sự chặn một PR phình quá phạm vi, phải bật thêm simplify.gate.enabled = true. Bản cài mới chưa bật cờ này, nên gate chỉ kiểm nhẹ và không chặn.

json
// .ck.json của dự án: bật chặn thật
{ "simplify": { "gate": { "enabled": true } } }

matchedSeverity() bỏ qua các cụm "don't ship" và "ship on", nên một prompt như "ship on Friday" cũng lọt qua. Muốn tắt gate cho mọi session trong một phạm vi, đặt CK_SIMPLIFY_DISABLED=1 trong settings.json, dưới key env.

workflow-artifact-gate: năm file JSON làm bằng chứng

Khi chạy đủ pipeline, mỗi giai đoạn để lại một file JSON ghi quyết định (artifact), giống hoá đơn sau mỗi bước. Hook này được thiết kế để gắn vào UserPromptSubmit và PreToolUse(Bash), nhưng không nằm trong bộ hook chạy sẵn sau khi cài mới; muốn dùng thì phải tự bật.

ArtifactGiai đoạnNội dung
context-snippets.jsonscout, planCác đoạn code đã đọc
risk-gate.jsonpredictCờ rủi ro cao, tự dừng
verification.jsonfix, cookChecklist năm điểm
review-decision.jsoncode-reviewKết luận của agent duyệt
adversarial-validation.jsonadversarialLượt kiểm đối kháng

Gate này có hai mức xử lý. Ở bước rủi ro như phát hành, push, mở PR hay deploy, hook có thể dừng luồng ngay và trả lý do về cho model (emitBlock()). Ở bước nhẹ hơn như hoàn tất hay commit, hook cho luồng đi tiếp nhưng thêm cảnh báo vào ngữ cảnh để model tự sửa (emitSoft()).

Chỗ hở 4, gate này phải tự bật: workflow-artifact-gate là lớp kiểm artifact mạnh nhất, nhưng bản cài mới chưa tự gọi nó. Muốn dùng, phải gắn hook trong settings.json và bật cấu hình trong .ck.json. Thiếu bước này thì phát hành, push, mở PR hay deploy đều không bị gate chặn.

Hard-gate XML trong file skill

Hook chỉ chặn được tool call. Có những lỗi không nằm ở tool call mà ở trình tự: code trước khi có kế hoạch, sửa trước khi dò. AgentKit xử lý bằng cách gắn khối <HARD-GATE> vào file markdown của skill.

xml
<HARD-GATE>
Do NOT write implementation code until a plan exists
and has been reviewed. Exception: --fast skips research
but still requires a plan step. User override: if user
explicitly says 'just code it', respect their instruction.
</HARD-GATE>

ak-cook và ak-fix mỗi skill có vài hard-gate như vậy: dò hoặc lập kế hoạch trước, làm đúng yêu cầu hoặc tìm đúng nguyên nhân gốc, không gây tác dụng phụ.

Vì sao gọi là "hard" mà vẫn chỉ là lời dặn: chữ "hard" dễ gây hiểu nhầm, vì nó không chặn bằng code. Đây là lời dặn trong prompt. Model bỏ qua thì không có exit 2 nào chặn lại. Bọc trong thẻ XML chỉ tạo tín hiệu mạnh hơn quy tắc thường để model khó tự biện minh cho việc đi tắt.

dev-rules-reminder: đưa quy tắc vào ngữ cảnh

dev-rules-reminder.cjs đăng ký ở UserPromptSubmit, chèn nội dung quy tắc vào mỗi prompt. Ở đây cần tách rõ hai lớp: hook là cơ chế chèn ngữ cảnh, còn quy tắc trong CLAUDE.md là nội dung được chèn. Ở bản này, mỗi cặp (sessionId, baseDir) chỉ được chèn lại sau 5 phút (TTL) để tránh đốt token.

FileChống lạiĐặc trưng
review-audit-self-decisionLượt audit đảo ngược quyết định đã xác nhậnQuyết định đã kiểm thì giữ nguyên
development-rulesBỏ test, dữ liệu giảYAGNI, KISS, DRY
team-coordination-rulesHai agent cùng sửa một chỗPhân quyền sở hữu theo glob
commit-messagesThân commit dài dòngMột dòng
orchestration-protocolTruyền nguyên lịch sử hội thoạiCô lập ngữ cảnh

Quy tắc là chữ trong ngữ cảnh, không phải code. Claude có thể lệch nếu prompt của người dùng đè lên. Bù lại, thêm hay sửa rất dễ. Lớp này hợp với quy ước phong cách hơn là với lớp bảo vệ bảo mật.

Guard skill: lớp chặn do người dùng gọi

Những skill dưới đây chỉ chạy khi bạn gọi tới:

SkillKhi dùngBắt được gì
ak-securityTrước khi phát hànhSecret, lỗ hổng đã công bố CVE (Common Vulnerabilities and Exposures), SQL injection (SQLi), cross-site scripting (XSS), path traversal
ak-predictTrước một tính năng rủi roNhiều persona tranh luận, kết luận GO, CAUTION hoặc STOP
ak-scenarioTrước khi triển khaiDò trường hợp biên theo nhiều chiều
ak-shipTrước khi mở PRDừng khi test lỗi, không bao giờ force-push

Agent code-reviewer chạy một checklist gồm: xử lý đồng thời, ranh giới lỗi, hợp đồng API (Application Programming Interface), tương thích ngược, kiểm tra đầu vào, xác thực và phân quyền, truy vấn N+1, rò rỉ dữ liệu, kiểm chứng dữ kiện. Đây là lớp chặn cuối trước khi merge.

Các chỗ hở đã biết

Đừng hiểu nhầm guardrail. Đây là các chỗ hở mình đã ghi nhận trên bản cấu hình ở trên:

  1. Lớp chặn truy cập file nằm ở hook. Bản cài mới dựa vào scout-block và privacy-block, không có danh sách permissions.deny riêng cho secret hay thư mục nặng.
  2. Bash được miễn privacy-block. Chỉ cảnh báo, không đi qua bước phê duyệt.
  3. workflow-artifact-gate phải tự bật. Gate mạnh nhất không chạy nếu chưa bật.
  4. simplify-gate mặc định chưa chặn. Cần bật rõ.
  5. simplify-gate trượt theo cách viết. "ship on Friday" được cho qua.
  6. .ckignore có thể phủ định node_modules. Hãy kiểm trực tiếp.
  7. Quy tắc là lời dặn. Claude có thể lệch.
  8. Khối HARD-GATE XML cũng là lời dặn. Nó còn có điều khoản "User override".

Ngoài ra, không có lớp chặn nào giới hạn số lần gọi hay hạn mức. Agent mất kiểm soát có thể gọi hàng nghìn lần Read, Glob, Bash. Hook của AgentKit không đếm số tool call và không tự dừng khi gần hết hạn mức. Giới hạn về hạn mức và chi phí nằm ở Claude Code, nhà cung cấp model hoặc tài khoản thanh toán, không nằm ở lớp guardrail này.

Nên làm và dễ nhầm

Phần này gom các thói quen mình thấy đáng giữ sau khi đọc kỹ bộ hook, cùng những chỗ người dùng hay hiểu sai.

Chủ đềNên làmDễ nhầm
Cấu hìnhĐọc cả settings.json và .ck.json sau khi cài.Sửa cấu hình toàn cục mà tưởng đang sửa cấu hình của repo.
simplify-gateMuốn chặn thật thì đặt gate.enabled = true.Tưởng nó đang chặn, trong khi mặc định chưa bật chế độ chặn.
Hook lỗiKiểm stderr xem có hook nào crash âm thầm không.Tưởng hook lỗi thì tool bị chặn; thực tế hook lỗi thường cho qua.
Quy tắc trong promptTưởng quy tắc trong prompt cũng chặn được như hook bằng code.
SecretKhi được hỏi phê duyệt đọc .env, đọc kỹ, đừng đồng ý theo phản xạ.Secret đã vào commit rồi mới trông vào privacy-block.
workflow-artifact-gateBật cho repo phát hành lên production.
node_modulesCần đọc thì ghi đè bằng .ckignore của dự án.

Sáu câu hỏi trước khi tin guardrail

  • settings.json đang gắn hook nào vào sự kiện nào?
  • .ck.json đã tắt hook nào, ở cả cấu hình ngoài và cấu hình con?
  • Session Claude Code hiện tại có đang bỏ qua hộp hỏi quyền không?
  • Có .ckignore của dự án ghi đè không? node_modules có bị mở bằng dấu ! không?
  • Các file quy tắc trong CLAUDE.md có đủ không?
  • Có hook nào crash âm thầm trong session này không (kiểm stderr)?

Thuật ngữ nhanh

Thuật ngữNghĩa gọn
HarnessLớp điều phối giữa model và máy: gửi lệnh tool, quản quyền, chạy hook. Là chỗ gắn guardrail.
HookScript nhỏ harness tự gọi ở thời điểm cố định trong vòng đời prompt, tool hay session để xen vào kiểm tra hoặc ghi trạng thái.
Sự kiện vòng đờiCác mốc hook được gọi: UserPromptSubmit (nhận prompt), PreToolUse (trước tool), PostToolUse (sau tool), Stop và SubagentStop (kết thúc session hoặc subagent).
Exit codeCon số một tiến trình trả về khi kết thúc. 0 cho qua, 2 chặn, 1 báo lỗi nhưng không chặn.
Fail-openKhi hook lỗi hoặc crash, harness cho tool chạy tiếp thay vì chặn. Lớp chặn tắt âm thầm.
TranscriptToàn bộ bản ghi hội thoại giữa người dùng và agent trong một session.
Ngữ cảnhVùng thông tin model "thấy" khi suy luận. Đầy file rác thì tốn chi phí và chất lượng giảm.
GlobMẫu khớp đường dẫn. **/*.ts là mọi file .ts ở mọi thư mục con.
SecretThông tin nhạy cảm như khoá API, khoá riêng (private key), thông tin đăng nhập. Lộ vào bản ghi hội thoại là rủi ro.
LOCLines of code, số dòng code, dùng để đo độ lớn của diff.
ArtifactFile JSON mỗi giai đoạn của pipeline để lại, ghi quyết định để giai đoạn sau kiểm tra.

Đọc đúng lớp, tin đúng mức

Khi agent có quyền rộng, đừng kết luận "đã cài AgentKit là an toàn". Trước khi tin guardrail, kiểm hai nơi: settings.json đang gắn hook nào, .ck.json đang bật tắt gì.

Mỗi lớp bảo vệ một kiểu rủi ro: hook chặn tool call, quy tắc nhắc hành vi, hard-gate giữ quy trình, guard skill chỉ chạy khi được gọi. Biết lớp nào đang chạy và lớp nào chỉ là lời dặn giúp bạn kiểm đúng chỗ, trước khi lỗi lọt vào PR rồi đi tiếp lên production.

Nếu bạn đang tự dựng hệ thống guardrail, có thể tham khảo các mẫu đã dùng trong AgentKit. Nếu muốn dùng luôn bộ hook, skill và workflow guardrail thay vì tự ghép từng mảnh, bạn có thể xem AgentKit. Như đã nói ở đầu bài, mình là maintainer của AgentKit; nếu bạn mua qua link giới thiệu này, mình nhận hoa hồng.

Đọc tiếp: Fable 5 và bài toán unknowns cho thấy các chốt kiểm này đứng ở đâu trong một pipeline thật, từ lập kế hoạch tới phát hành.

Dùng bài này trong agent của bạn

Lấy API key

Chép đoạn dưới, dán vào Claude Code, Codex hay agent bạn đang dùng. Agent đọc bài rồi đối chiếu với repo đang mở.

Dán vào agent
Đọc bài "Guardrail trong Claude Code và AgentKit (2/2): từng lớp chặn, chỗ hở và cách dùng" trên modernEngineer rồi áp dụng vào repo này.
1. Gọi tool content_get của MCP server modernengineer với locale "vi", slug "guard-rails-claude-code-agentkit-2-guard-layers". Nếu chưa nối MCP hoặc bị từ chối quyền, đọc thẳng trang https://modernengineer.dev/vi/library/guard-rails-claude-code-agentkit-2-guard-layers.
2. Tóm tắt các bước chính của bài, chỉ ra bước nào áp dụng được cho repo này.
3. Đề xuất thay đổi cụ thể và hỏi tôi trước khi sửa file.
Nối MCP cho Claude Code (một lần)
terminal
claude mcp add --transport http modernengineer \
  https://api.modernengineer.dev/mcp \
  --header "Authorization: Bearer <API key>"
Cách nối Codex, Cursor và client khác

Bài mở cho mọi người: chưa nối MCP thì agent vẫn đọc được thẳng từ link bài.

Phiên bản
v1.0.0
Cập nhật
09/06/2026
Giấy phép
Bảo lưu mọi quyền
Slug
guard-rails-claude-code-agentkit-2-guard-layers