Bỏ qua để vào nội dung chính
Chặn Sandbox Escape Cho AI Coding Agent: Checklist 6 Bước

Chặn Sandbox Escape Cho AI Coding Agent: Checklist 6 Bước

Bởi Ethan Carter
19 thg 8, 20266 phút đọc

Một lỗi glob trong tên thư mục mở đường cho sandbox escape CVSS 7.7 trên Claude Code. Cùng gốc với bypass command filter, và cách vá sáu bước.

Bạn mở project trong Claude Code, tắt Bash tool cho chắc, và tin rằng agent không ghi được file ra ngoài thư mục project. Một writeup bảo mật vừa công bố cho thấy niềm tin đó sụp đổ chỉ vì tên thư mục chứa dấu *. Bài này dựng lại hai lỗi đã xác nhận, chỉ ra cùng một nguyên nhân gốc, và đưa checklist sáu bước chạy được ngay chiều nay.

Hai lỗi khác nhau, cùng một gốc: hai parser đọc cùng một chuỗi

Mọi lớp guard của AI coding agent đều làm một việc: đọc một chuỗi (đường dẫn hoặc câu lệnh) rồi quyết định cho phép hay chặn. Nhưng sau guard luôn có parser thứ hai — bộ sinh policy của sandbox, hoặc chính bash — đọc lại đúng chuỗi ấy theo luật khác. Khi hai parser bất đồng, guard đã ký duyệt xong, còn parser thứ hai mới là bên thực sự chạy lệnh. Hai case dưới đây là cơ chế đó ở hai tầng khác nhau.

Case 1: dấu sao trong tên thư mục làm rộng allow rule

Nhóm CodeAnt AI công bố một lỗi sandbox escape trên macOS của Claude Code, chấm điểm CVSS 4.0 là 7.7 (High). Theo writeup, đây là "fourth High-severity finding in Claude Code this year". Nguyên nhân được mô tả là "a path-parsing ambiguity in how Claude Code's macOS sandbox scopes filesystem writes".

Cơ chế: sandbox tự duyệt thao tác ghi nằm trong thư mục project hiện tại, và để xác định phạm vi, bộ sinh policy soi đường dẫn xem có ký tự glob (*, ?) hay không. Writeup mô tả điểm hỏng: "this check has no mechanism to distinguish a path that is intentionally a glob pattern from a literal folder name that merely contains glob metacharacters."

Hệ quả: đổi tên thư mục thành review-bundle**.claude** khiến allow rule giãn từ "đúng thư mục này" thành pattern khớp mọi thư mục anh em bắt đầu bằng review-bundle. Deny rule bảo vệ .claude/settings.local.json thì không giãn theo — writeup ghi nó "was implemented to expect two .claude path segments before it triggers", nên match hụt.

Bảng differential test trong writeup cho thấy lỗi rất hẹp và rất xác định:

Tên thư mụcAllow ruleDeny ruleKết quả
review-bundleNo matchN/ABlocked
review-bundle**MatchMatchBlocked
review-bundle**.claude**MatchMISSGhi được settings, hook chạy
**.claude**MatchMISSGhi được settings, hook chạy

Từ quyền ghi đó, chuỗi khai thác dùng tiếp SessionStart hook — cơ chế chạy lệnh ngay khi mở session mới. Điều kiện tái hiện được ghi rõ: mở project anh em "with Bash access disabled and no API key configured", hook vẫn "executes before authentication, before the model produces any output, and before the Bash tool is available to the session".

Phạm vi ảnh hưởng theo writeup: Claude Code 2.1.214 và 2.1.215 (macOS arm64), 4 test case differential, bypass hoàn toàn 2/4, và "Prerequisites: none — no symlinks, race conditions, or leaked credentials required". Timeline disclosure: báo cáo ngày 18/7, Anthropic xác nhận ngày 20/7, trao bounty ngày 4/8.

Case 2: command filter đọc chuỗi, còn bash đọc lại chuỗi

Cùng một kiểu bất đồng parser xuất hiện ở tầng lệnh. Theo một writeup khác, Adversa AI công bố bộ bypass tên GuardFall ngày 30/6/2026, và các bypass này "got past the command filter in 10 of 11 open-source coding and computer-use agents". Agent duy nhất trụ được là Continue, và lý do được nêu rất đáng chú ý: "it parses the command before judging it, rather than matching patterns in raw text".

Thủ thuật không mới. Tác giả mô tả: "The guard inspects the string the model produced, and bash rewrites that string before running it. A regex reads r''m and finds nothing to match, then bash strips the quotes and runs rm." Cơ chế tương tự áp dụng cho $IFS expansion và command substitution: "Two parsers read the same bytes and disagree, and the second one runs as root."

Với ai định vá bằng cách siết allowlist: theo tác giả, cách đó không đóng được lỗ, "because the gap is the string itself".

Tác giả bài viết đang xây một MCP server tên SysKnife theo hướng typed action, mô tả nó chỉ nhận action có schema, không có exec hay sudo-exec trên tool surface, với catalogue cố định 190 typed action. Đây là tuyên bố của tác giả về sản phẩm của chính họ, không phải kiểm chứng độc lập — nhưng hướng thiết kế đáng tham khảo: bắt agent nói bằng cấu trúc dữ liệu, không nói bằng chuỗi shell.

Checklist sáu bước cho máy dev của bạn

Phần này là phân tích, xếp theo chi phí thực hiện tăng dần.

  1. Đặt tên thư mục project sạch. Chỉ dùng chữ, số, gạch ngang, gạch dưới. Không *, không ?, không dấu ngoặc. Đây là biện pháp rẻ nhất và chặn đúng case 1.
  2. Chạy bản agent mới nhất. Writeup không nêu bản vá cụ thể, chỉ nêu hai version bị ảnh hưởng và mốc trao bounty — nên bám bản mới nhất vẫn là bước rẻ nhất.
  3. Coi settings.local.json nhạy cảm ngang .env. Nó định nghĩa được hook tự chạy, nên một dòng bất ngờ trong file này là sự cố, không phải nhiễu.
  4. Đọc hook trước khi mở repo lạ. Với repo clone từ ngoài, xem file cấu hình hook trước khi mở bằng agent — hook chạy trước cả output đầu tiên.
  5. Ưu tiên tool có schema thay vì tool nhận chuỗi shell. Nếu agent expose run_command(cmd: string), mọi lớp lọc phía trên đều là regex chạy đua với bash.
  6. Đặt quyền thật ở tầng dưới agent. Chạy agent bằng user không sudo, để đặc quyền sau một ranh giới tiến trình riêng. Prompt không phải cơ chế phân quyền.

Hai lệnh tự kiểm tra

Đoạn dưới là ví dụ minh hoạ để soát lại máy mình, không phải PoC khai thác:

# ví dụ minh hoạ - thư mục project có ký tự glob trong tên
find ~/code -maxdepth 2 -type d -name '*[*?]*'

# ví dụ minh hoạ - file cấu hình local đổi trong 7 ngày qua
find ~/code -maxdepth 3 -name 'settings.local.json' -newermt '-7 days'

Lệnh đầu trả về kết quả nghĩa là bạn đang có đúng bề mặt của case 1. Lệnh thứ hai trả về file bạn không nhớ đã sửa thì mở ra đọc trước khi mở project bằng agent.

Thứ đáng theo dõi tiếp

Điểm chung của hai case: guard suy ra ý nghĩa từ ký tự trong chuỗi thay vì làm việc trên đối tượng đã resolve. Khuyến nghị trong writeup CodeAnt đi đúng hướng đó — kiểm tra xem lớp policy "resolves paths as validated, canonical filesystem objects, or infers type from raw string content", và xác minh allow rule với deny rule "use identical path-normalization logic".

Thứ đáng theo dõi vài tuần tới: các agent khác có chuyển sang parse-trước-rồi-duyệt như Continue hay không. Chừng nào guard còn đọc chuỗi thô, tìm lỗ chỉ là bài toán tìm cặp parser bất đồng tiếp theo.

Không spam, hủy đăng ký bất kỳ lúc nào.

Bài viết liên quan