สิทธิ์, แซนด์บ็อกซ์ และพาธที่ถูกป้องกันใน Claude Code — อ่านสเปกทางการ 3 ฉบับเพื่อหาประตูจริงที่หยุด AI ไม่ให้แก้ไฟล์ตั้งค่าของตัวเอง
บทนำ
ฉันมีข้อตกลงหลายข้อกับผู้ช่วย AI เขียนโค้ดส่วนตัว หนึ่งในนั้นคือ “AI ไม่แก้ไฟล์ตั้งค่าของตัวเอง (ชุดกฎว่าอะไรอนุญาตและอะไรปฏิเสธ)” ข้อตกลงไม่ใช่สิ่งที่ตกลงครั้งเดียวแล้วทิ้งไว้ มันต้องถูกตรวจอยู่เรื่อย ๆ ว่ายังคงอยู่จริงหรือไม่ บทความนี้บันทึกการอ่านแหล่งข้อมูลปฐมภูมิทางการ 3 ฉบับ — เรื่องสิทธิ์, แซนด์บ็อกซ์ (สภาพแวดล้อมการรันแบบแยกส่วน) และพาธที่ถูกป้องกัน — เพื่อการตรวจนั้น
ก่อนอ่าน ฉันคิดว่า “ใช้กลไกการแยกส่วนที่เรียกว่าแซนด์บ็อกซ์น่าจะให้การป้องกันที่แข็งที่สุด” พอถึงตอนจบ คำทำนายนั้นผิด และทั้งเหตุผลที่มันผิด กับคำตอบที่พบมาแทน ต่างก็เป็นสิ่งที่คุณไม่มีทางรู้ได้ถ้าไม่ลงมือตรวจจริง
ลำดับการประเมิน กับกฎหนึ่งข้อที่ไม่เคยถูกเรียกดูเลย
กฎสิทธิ์ถูกประเมินตามลำดับ deny, ask, allow ข้อความทางการระบุว่า
Claude Code checks file permissions against
Edit(path)andRead(path)rules only. If you write a path rule forWrite,NotebookEdit,Glob, or the legacyMultiEdittool instead, Claude Code accepts the rule but never consults it, and warns at startup.
นั่นคือ กฎที่เขียนต่อพาธไฟล์จะถูกเรียกดูจริงเพียง 2 ชนิดเท่านั้น คือ Edit และ Read ถ้าคุณเขียนกฎพาธต่อ Write มันจะถูกรับเข้ามาในฐานะการตั้งค่า แต่ไม่เคยถูกใช้ในการตัดสินแม้แต่ครั้งเดียว การทบทวนการตั้งค่าของฉันเองพบกฎพาธ Write แบบนั้นอยู่ 1 ข้อ ไม่มีความเสียหายจริงเกิดขึ้น — เพราะมีกฎ Edit ที่ครอบตำแหน่งเดียวกันวางอยู่ข้าง ๆ และครอบส่วนของเครื่องมือ Write ไว้ด้วย แต่สภาพ “กฎที่คุณคิดว่าเขียนไว้ ไม่เคยถูกประเมินสักครั้ง” คือสภาพที่จะอยู่อย่างนั้นไปเรื่อย ๆ ถ้าไม่มีใครสังเกต
ยังมีกับดักอีกอันหนึ่ง อยู่ที่วิธีเขียนพาธ
A pattern like
/Users/alice/fileisn’t an absolute path. The single leading slash anchors at the settings source, not the filesystem root.
พาธที่ขึ้นต้นด้วยสแลชตัวเดียวไม่ถูกตีความเป็นพาธสัมบูรณ์บนดิสก์ แต่เป็นพาธสัมพัทธ์กับ “ที่ที่ไฟล์ตั้งค่านั้นอยู่” ถ้าจะชี้ไปยังพาธสัมบูรณ์บนดิสก์ คุณต้องใช้รูปแบบที่มีสแลชสองตัว สตริงเดียวกันที่ขึ้นต้นด้วย ”/” มีความหมายต่างกันโดยสิ้นเชิง — ซึ่งก็คือ กฎที่คุณเขียนอาจกำลังชี้ไปที่อื่น ไม่ใช่ที่ที่คุณเล็งไว้
การตั้งค่าที่ฉัน “เอาออกแล้ว” กลับมาอยู่ที่เดิมมา 4 วัน
ข้อค้นพบที่ใหญ่ที่สุดไม่ใช่เรื่องของสเปกสิทธิ์ แต่คือ ข้อตกลงที่เราน่าจะยุติกันไปแล้วในอดีต จริง ๆ แล้วมันย้อนกลับมา
เมื่อก่อนฉันตัดสินใจว่าจะ “เอาสิทธิ์แก้ไฟล์ตั้งค่าออกจากรายการอนุญาตของ AI” บันทึกของการตัดสินใจนั้นเขียนว่า “เอาออกแล้ว” ในรูปปัจจุบันกาล แต่การกระทบยอดกับไฟล์ตั้งค่าจริงและประวัติการเปลี่ยนแปลงของมัน เล่าเรื่องอีกแบบหนึ่ง
[実測] 設定ファイルの変更履歴(要旨)
1本目のコミット: 設定書き換え権限を許可リストから外す(判断どおり)
↓ 3時間14分後
2本目のコミット: 別の不具合を切り分けるため、設定ファイルを編集する必要が生じ
書き換え権限が許可リストに戻る
↓
以後の変更でも、外れたままにはならず今日まで許可リストに残存
บันทึกของการตัดสินใจยังคงเขียนว่า “เอาออกแล้ว” และไม่เคยถูกอัปเดต ขณะที่การตั้งค่าจริงกลับคืนมาหลังจากนั้น 3 ชั่วโมง 14 นาที ถ้าดูแค่ด้านใดด้านหนึ่งในสองด้าน คุณจะไม่มีวันสังเกตเห็น บันทึกของการตัดสินใจ กับสภาพที่การตัดสินใจนั้นถูกสะท้อนออกมาจริง ต้องถูกตรวจแยกกัน ไม่อย่างนั้นความเบี่ยงเบนจะไม่ถูกมองเห็น
สิ่งที่ฉันเข้าใจว่าเป็นกำแพงแข็งที่สุด กลับไม่มีให้ใช้ในสภาพแวดล้อมของฉันด้วยซ้ำ
กฎสิทธิ์มี “ช่องเลี่ยงทางเชลล์” กฎ allow และ deny สำหรับการดำเนินการกับไฟล์ทำงานกับคำสั่งที่ Claude รู้จักเอง แต่ปิดเส้นทางที่โปรแกรมใด ๆ เปิดและเขียนไฟล์ภายในตัวมันเองไม่ได้
They don’t apply to arbitrary subprocesses that read or write files indirectly, like a Python or Node script that opens files itself. For OS-level enforcement that blocks all processes from accessing a path, enable the sandbox.
พออ่านประโยคนั้น ฉันก็ยึด “กลไกที่บังคับใช้ในระดับ OS = แซนด์บ็อกซ์” เป็นคำตอบจริง แต่พอเปิดสเปกของแซนด์บ็อกซ์ ไม่กี่บรรทัดแรกของมันบอกว่า
The sandbox is built into Claude Code and runs on macOS, Linux, and WSL2. Native Windows is not supported. On Windows, run Claude Code inside a WSL2 distribution.
สภาพแวดล้อมการทำงานของฉันคือเทอร์มินัลที่รันบน Windows โดยตรง (การตั้งค่าที่ไม่ผ่าน WSL ซึ่งเป็นกลไกสำหรับรัน Linux ภายใน Windows) กลไกที่ฉันยึดว่าเป็น “คำตอบจริง” ใช้ไม่ได้ในสภาพแวดล้อมของฉัน ตั้งแต่ก่อนที่ฉันจะไปตรวจเสียอีก ฉันตัดสินก้าวถัดไปจากประโยคเดียวในเอกสารฉบับแรก และเขียน “คำตอบ” ลงไปก่อนจะเปิดสเปกของกลไกนั้นเอง — นั่นคือความล้มเหลวในลำดับการอ่าน ไม่ใช่ความล้มเหลวของสเปก คุณต้องอ่านสเปกจนจบก่อนจะเรียกมันว่า “คำตอบ”
ในที่ของกำแพงที่ใช้ไม่ได้ มีอีกกำแพงยืนอยู่ตรงนั้นมาตลอด
หลังรู้ว่าแซนด์บ็อกซ์ใช้ไม่ได้ ก็มีเบาะแสอยู่ที่อื่นในสเปกฉบับเดียวกันนั้น
The permission system has its own protected paths, which control what Claude Code approves before a tool runs; the sandbox’s list applies to a command that is already running.
แยกต่างหากจากแซนด์บ็อกซ์ กลไกที่เรียกว่า “พาธที่ถูกป้องกัน” มีอยู่อย่างเป็นอิสระในฝั่งของระบบสิทธิ์ ด้วยความที่มันไม่ใช่การแยกส่วนระดับ OS มันจึงอาจทำงานบน Windows ได้ด้วย การตรวจสเปกยืนยันว่าเป็นอย่างนั้นพอดี
Writes to a small set of paths are never auto-approved, except in
bypassPermissionsmode and in planning sessions with bypass permissions available.permissions.allow rules in settings files do not pre-approve protected-path writes. The safety check runs before Claude Code evaluates allow rules from settings, so an entry such as
Edit(.claude/**)in~/.claude/settings.jsonor.claude/settings.jsondoes not change the per-mode outcome in the table above.
การเขียนไปยังพาธที่ถูกป้องกัน จะไม่มีวันถูกอนุมัติอัตโนมัติ ไม่ว่ารายการอนุญาตจะเขียนไว้อย่างไร โดยการออกแบบ การตรวจความปลอดภัยนี้ทำงานก่อนที่กฎ allow จะถูกประเมิน ไดเรกทอรีที่เก็บไฟล์ตั้งค่าของฉันเองอยู่ในการป้องกันนั้นทั้งก้อน
และในที่สุด แม้กำแพงนั้นก็ไม่ใช่ “ประตูของมนุษย์”
เรื่องยังไม่จบตรงนั้น ต่อให้การเขียนไปยังพาธที่ถูกป้องกัน “ไม่มีวันถูกอนุมัติอัตโนมัติ” การจัดการก็ยังต่างกันไปตามโหมดการทำงาน ในโหมดที่ฉันใช้ มันถูกประมวลผลดังนี้
Actions matching your allow, ask, or deny rules resolve immediately. Writes to protected paths route to the classifier even when an allow rule matches. … Everything else goes to the classifier.
การเขียนไปยังพาธที่ถูกป้องกันถูกส่งต่อ ไม่ใช่ไปยังกล่องยืนยันสำหรับมนุษย์ แต่ไปยัง “ตัวจำแนก” (classifier) (กลไกที่ตัว AI เองเป็นผู้ตัดสินบนพื้นฐานของบทสนทนาก่อนหน้า) ตัวจำแนกคือการตัดสินของตัวโมเดลเอง ไม่ใช่ประตูที่คนเลือก ใช่ หรือ ไม่ ณ ตรงนั้น และข้อความทางการก็มีหมายเหตุที่คมอยู่หนึ่งข้อเกี่ยวกับการตัดสินของตัวจำแนก
the classifier blocks matching actions even when the default rules would allow them … Claude’s own judgment that a condition was met does not lift it … a boundary can be lost if context compaction removes the message that stated it. For a hard guarantee, add a deny rule instead.
เส้นแบ่งที่ถูกสื่อสารในบทสนทนาเท่านั้น — “อย่าแตะตรงนี้นะ” — อาจหายไปพร้อมกับข้อความเก่า ๆ ตอนที่บทสนทนาถูกย่อ วิธีเดียวที่ได้ผลอย่างเชื่อถือได้ตามที่เอกสารทางการระบุ คือการเขียนกฎ deny ให้ชัดเจน การสื่อสารข้อตกลงในบทสนทนา กับการเขียนมันลงในไฟล์ตั้งค่าในฐานะกฎ deny ต่างกันที่ความแข็งแรงของการรับประกัน
เส้นทางที่เดินผ่านเอกสาร
เริ่ม: ข้อตกลง "อย่าให้มันแก้ไฟล์ตั้งค่า" ยังคงอยู่จริงหรือไม่
│
├─▶ อ่าน permissions.md
│ ├─ ยืนยันลำดับการประเมิน (deny→ask→allow)
│ ├─ พบว่ากฎ Write จริง ๆ แล้วไม่เคยถูกเรียกดูเลย
│ ├─ พบว่าวิธีเขียนพาธเปลี่ยนที่ที่มันชี้ไป
│ └─ กระทบยอดการตัดสินใจในอดีตกับไฟล์ตั้งค่าจริง
│ └─ ⚠️ สิ่งที่ "เอาออกแล้ว" กลับมาหลังจากนั้น 3 ชั่วโมง 14 นาที
│
├─▶ เจอประโยคที่ทำให้แซนด์บ็อกซ์ดูเหมือน "คำตอบจริง"
│ └─▶ เปิด sandboxing.md แล้วตรวจ
│ └─ ⛔ ไม่รองรับ Windows แบบเนทีฟ = ใช้ไม่ได้ในสภาพแวดล้อมของฉัน
│ └──(การแก้ไข, เส้นย้อนกลับ)──▶ ถอนข้อสรุปก่อนหน้า
│
├─▶ เจอเบาะแสในเอกสารฉบับเดียวกันว่า "พาธที่ถูกป้องกันเป็นคนละกลไก"
│ └─▶ เปิด permission-modes.md แล้วตรวจ
│ └─ ✅ พาธที่ถูกป้องกันไม่ขึ้นกับ OS = ทำงานบน Windows ด้วย
│ └─ แต่การจัดการต่างกันไปตามโหมดการทำงาน
│ └─ ในโหมดของฉันมันไปที่ตัวจำแนก
│ └─ ตัวจำแนกไม่ใช่ประตูของมนุษย์
│ └─ วิธีที่เชื่อถือได้ตามเอกสารทางการ = กฎ deny
ความต่างระหว่าง “ข้อตกลง” กับ “กำแพง” ที่เรียนรู้ได้จากการวัดเท่านั้น
สิ่งที่เหลืออยู่หลังเอกสาร 3 ฉบับ ไม่ใช่คำตอบเดียวแบบ “ทำแบบนี้แล้วปลอดภัย” แต่คือ วัตถุดิบสำหรับซ้อนกำแพงที่แข็งแรงต่างกันให้ถูกลำดับ เส้นแบ่งที่พูดในบทสนทนาอาจหายไปได้ รายการอนุญาตไม่มีความหมายในขั้นก่อนหน้าพาธที่ถูกป้องกัน ตัวจำแนกคือการตัดสินของตัวโมเดลเอง ไม่ใช่การอนุมัติโดยคน และวิธีที่เอกสารทางการระบุว่าเชื่อถือได้ที่สุด คือกฎ deny ที่ชัดเจน เขียนลงในไฟล์ตั้งค่า
ยังมีอีกหนึ่งสิ่งที่ได้กลับมา นอกเหนือจากเนื้อหาของเอกสาร: วินัยที่ว่า “อย่าตัดสินก้าวถัดไปจากประโยคเดียวของแหล่งข้อมูลปฐมภูมิ” ณ จุดที่ฉันเขียนว่าแซนด์บ็อกซ์คือคำตอบ ฉันยังไม่ได้เปิดสเปกของมันเลยด้วยซ้ำ อย่าเรียกอะไรว่าข้อสรุป จนกว่าคุณจะอ่านสิ่งที่การอ้างอิงนั้นชี้ไปจนจบ นั่นคือเหตุผลที่คำตอบพลิกไปหนึ่งครั้งตรงนี้
ฉันออกเดินไปหากำแพงแข็ง ๆ หนึ่งบาน และสิ่งที่ได้กลับมาคือ แบบร่างสำหรับเรียงกำแพงที่แข็งแรงต่างกันให้ถูกลำดับ การรู้ว่าแผ่นไหนคือแผ่นสุดท้าย ได้ผลดีกว่าการทำให้แผ่นนั้นหนาขึ้น