ข้าม​ไป​ยัง​เนื้อหา

Excessive agency & least privilege: หด blast radius เมื่อ detection พลาด

บท4 (input guard) กับ​บท5 (output guard) เป็น​ชั้น detection — มัน​พยายาม จับ injection ก่อน loop จะ dispatch tool และ กรอง output ก่อน​มัน​ไหล​ออก แต่ honesty spine ของ​คอร์ส​นี้​พูดตรงๆ มา​ตั้งแต่​บท1: detection ไม่มี​ทาง​สมบูรณ์ — Anthropic วัด​การ​ป้องกัน​ที่​ดี​ที่สุด​ของ​ตัวเอง​แล้ว​ยัง​เหลือ ~1% ที่​ลอด​ได้ และ 1% นั้น​คือ “meaningful risk” คำถาม​ของ​บท​นี้​จึง​ไม่ใช่ “จะ​จับ​ให้​ได้ 100% ยังไง” (จับ​ไม่​ได้) แต่​เป็น — เมื่อ injection ลอด​ทุก​ชั้น detection แล้ว​สั่ง​ให้ agent issueRefund ให้​ผู้​โจมตี ความ​เสียหาย​จะ​ใหญ่​แค่​ไหน? บท​นี้​คือ​ชั้น containment: ลด​สิ่ง​ที่ agent ทำได้ ให้​เหลือ​น้อย​ที่สุด แล้ว​คร่อม action ที่​อันตราย​ที่สุด​ด้วย​ด่าน​มนุษย์

📦 code ตัวอย่าง

บท​นี้​ต่อยอด agent Order ตัว​เดิม (tool getOrder / getDeliveryStatus / issueRefund จาก #15, resilient runtime จาก #17) — repo kaen-food-ordering (กำลัง​จัด​ทำ) เรา​ไม่​เพิ่ม tool ใหม่ แต่ หด สิทธิ์​ของ tool ที่​มี แล้ว​ห่อ issueRefund ด้วย approval gate ทุก​กติกา API ฝั่ง​แชต​จาก #15 ยัง​ยึด​เดิม​ทุก​ข้อ — model id เป็น alias เปล่า claude-opus-4-8 (ลง​วัน​ที่ 2026-07 กำกับ ไม่​ต่อ suffix) และ native approval surface (ApprovalRequiredAIFunction ฯลฯ) ยืนยัน​ไว้​กับ Microsoft.Extensions.AI version 10.7.0 — re-pin กับ version ที่​อยู่​ใน .csproj จริง​ตอน build (คอร์ส​นี้​เดิน​บน 10.8.0 GA — เช็กว่า​ชื่อ type/member ยัง​ตรง)

Excessive AgencyExcessive AgencyOWASP LLM06 — agent มี functionality, permission หรือ autonomy 'มาก​เกิน​งาน​ที่​ต้อง​ทำ' เมื่อ​ศัตรู​บิด output ได้​สำเร็จ agent จึง​ลงมือ​ทำ​สิ่ง​อันตราย​จริง​ได้ สาม​ราก​เหตุ: excessive functionality (tool ที่​ไม่​จำเป็น เช่น general runSql/httpGet), excessive permissions (credential กว้าง​เกิน), excessive autonomy (issueRefund ยิง​เอง​โดย​ไม่มี​คน​ยืนยัน) — รักษา​ด้วย least privilege + approval gate + blast-radius capProcess คือ​ช่อง​โหว่​ที่ agent มี functionality, permissions หรือ autonomy มาก​เกิน​กว่า​ที่​งาน​ต้องการ — พอ​ผู้​โจมตี​บิด output ของ model ได้ (ผ่าน injection ที่​ลอด​บท4/5 มา) agent ก็​ลงมือ​ทำ​สิ่ง​ที่​เป็น​อันตราย​จริง OWASP LLM06 ตั้งต้น​จาก​ข้อเท็จจริง​ที่​ว่า agent มี​สิทธิ์​ลงมือ อยู่​แล้ว (S6, verbatim):

“An LLM-based system is often granted a degree of agency by its developer – the ability to call functions or interface with other systems via extensions.”

OWASP แยก root cause ออก​เป็น​สาม​อย่าง map แต่ละ​อัน​ลง​บน agent Order แล้ว​จะ​เห็น​ว่า​แต่ละ​อัน​มี​ทาง​รักษา​ต่าง​กัน:

  • excessive functionality (ความ​สามารถ​เกิน) — agent มี tool ที่​งาน​ไม่​ต้อง​ใช้ ทาง​รักษา: อย่า​ให้ tool ที่​ไม่​จำเป็น getOrder / getDeliveryStatus / issueRefund เป็น​ชุด minimal อยู่​แล้ว — บท​นี้​สอน​ว่า​ทำไม​คุณ ไม่​เคย เพิ่ม tool กว้างๆ อย่าง runSql หรือ httpGet
  • excessive permissions (สิทธิ์​เกิน) — tool ที่​มี รัน​ด้วย credential ที่​กว้าง​เกิน ทาง​รักษา: issueRefund ได้ credential เฉพาะ​ของ​ตัวเอง มี cap ยอด​เงิน​ฝั่ง server ไม่ใช่ ambient authority ของ​ทั้ง agent
  • excessive autonomy (อิสระ​เกิน)issueRefund ยิง​ได้​เอง​โดย​ไม่มี​มนุษย์​ยืนยัน ทาง​รักษา: ด่าน​อนุมัติ​โดย​มนุษย์ — control เอก​ของ​บท​นี้

Least PrivilegeLeast Privilegeหลัก​ให้ agent และ tool ถือ​สิทธิ์ 'น้อย​ที่สุด​เท่า​ที่​งาน​ต้อง​ใช้' — ไม่​เพิ่ม general tool, ให้ issueRefund ใช้ scoped credential + server-side amount cap แทน ambient authority, เปิด tool แบบ contextual/dynamic (เสนอ refund tooling เฉพาะ​ตอน​บทสนทนา​เป็น​เรื่อง refund จริง — SAIF, S18) Anthropic: 'so that a successful injection can do minimal damage' — เป็น upper bound ของ blast radius เมื่อ detection พังArchitecture คือ​หลัก​ว่า agent ควร​ถือ​สิทธิ์​และ​ความ​สามารถ น้อย​ที่สุด​เท่า​ที่​งาน​ต้องการ — ไม่ใช่​มาก​ที่สุด​เท่า​ที่​สะดวก Anthropic วาง​หลัก​นี้​เป็น​ตัว​จำกัด​ความ​เสียหาย​ของ injection โดยตรง (S13, verbatim):

“Apply the principle of least privilege so that a successful injection can do minimal damage: don’t give Claude access to secrets it doesn’t need, run tools in sandboxed environments, and scope permissions as narrowly as possible.”

สังเกต​วลี “so that a successful injection can do minimal damage” — นี่​คือ mindset ของ​ทั้ง​บท least privilege ไม่​ได้​พยายาม กัน injection (บท4/5 ทำ​หน้าที่​นั้น​และ​ทำ​ไม่​สมบูรณ์) แต่​มัน สมมติ​ว่า injection สำเร็จ​แล้ว แล้ว​ถาม​ว่า​ความ​เสียหาย​จะ​เล็ก​แค่​ไหน

จุด​ที่​ทำ​พลาด​กัน​บ่อย​คือ static tool exposure — ยัด tool ทุก​ตัว​เข้า ChatOptions.Tools ทุก​เทิร์น​ไม่​ว่า​บทสนทนา​จะ​เป็น​เรื่อง​อะไร ทั้ง​ที่ 90% ของ session เป็น​แค่ “ออเดอร์​ฉัน​อยู่​ไหน” ที่​ไม่​ต้อง​แตะ issueRefund เลย ทาง​ที่​ดี​กว่า​คือ contextual / dynamic exposure — เปิด tool คืน​เงิน​ให้ model เห็น ต่อ​เมื่อ บทสนทนา​กลาย​เป็น​เรื่อง​ขอ​คืน​เงินจริงๆ Google SAIF วาง​หลัก​นี้​ว่า​ให้​ใช้ least privilege เป็น ขอบ​บน ของ​สิทธิ์ agent และ​สิทธิ์​ควร​เป็น​แบบ “contextual and dynamic” (S18) — tool ที่ model ไม่​เห็น คือ tool ที่ injection สั่ง​เรียก​ไม่​ได้

Approval gate: ด่าน​มนุษย์​บน action ที่​ย้อน​คืน​ไม่​ได้ — native เป็น​ทาง​หลัก

หัวข้อ​ที่​มีชื่อ​ว่า “Approval gate: ด่าน​มนุษย์​บน action ที่​ย้อน​คืน​ไม่​ได้ — native เป็น​ทาง​หลัก”

Approval GateApproval Gatehuman-in-the-loop ที่​กั้น action สำคัญ/ย้อน​ไม่​ได้ (issueRefund) ให้ 'คน' อนุมัติ​ก่อน — path หลัก​คือ native: ApprovalRequiredAIFunction → ToolApprovalRequestContent → ToolApprovalResponseContent (FunctionInvokingChatClient เคารพ marker) ⚠️ ApprovalRequiredAIFunction แค่ MARK ไม่ enforce ('it is the responsibility of the invoker to obtain that approval') — invoker ต้อง block รอ​คนจริง ๆ เอง และ​เพราะ approval stickiness ให้​ตั้ง AllowMultipleToolCalls=false; gate เฉพาะ action สำคัญ ไม่ใช่​ทุก​อย่าง (approval fatigue ~93% อนุมัติ​ผ่าน, S17)Architecture คือ​ด่าน​ที่ หยุด loop ไว้ ก่อน action ที่​มี​ผล​ข้าง​เคียง​จะ​รัน แล้ว​ส่ง​การ​ตัดสิน​ใจ​ให้​มนุษย์​ยืนยัน OWASP LLM06 เรียก​มันตรงๆ (S6, verbatim):

“Utilise human-in-the-loop control to require a human to approve high-impact actions.”

Microsoft.Extensions.AI มี native surface สำหรับ​ด่าน​นี้​ตั้งแต่ 10.7.0 — และ​มัน​คือ ทาง​หลัก (นี่​เป็นการ​แก้​โน้ต​เก่า​ของ #17 ที่​บอกว่า “hand-roll ไว้​ก่อน”) วิธี​คือ mark tool ที่​ต้อง​ขอ​อนุมัติ​ด้วย ApprovalRequiredAIFunction แล้ว FunctionInvokingChatClient (ตัว loop จาก #15) จะ ไม่ รัน tool นั้น​เอง แต่​จะ คาย คำขอ​อนุมัติ​กลับ​ออก​มา​ให้ app แทน:

using Microsoft.Extensions.AI;
AIFunction issueRefundFn = AIFunctionFactory.Create(IssueRefund);
var options = new ChatOptions
{
Tools =
[
getOrder, // read-only — เปิดได้อิสระ ไม่ผ่าน gate
getDeliveryStatus, // read-only — sensor รันซ้ำได้ไม่เจ็บ
new ApprovalRequiredAIFunction(issueRefundFn) // write — mark ว่าต้องมนุษย์อนุมัติ
],
AllowMultipleToolCalls = false // จำเป็น — กัน caveat "stickiness" ด้านล่าง
};

เมื่อ loop ไป​เจอ issueRefund มัน​จะ ไม่ ยิง​คืน​เงิน แต่​คืน message ที่​มี ToolApprovalRequestContent (พก tool call + correlation id) กลับ​ออก​มา loop หยุด​ค้าง​ไว้ — เงิน​ยัง ไม่ ถูก​คืน app ของ​คุณ​เอา​คำขอ​นั้น​ไป​ถาม​มนุษย์ ได้ yes/no แล้ว​ส่ง​กลับ​เข้า history เป็น ToolApprovalResponseContent:

// ctor: (string requestId, bool approved, ToolCallContent toolCall)
var decision = new ToolApprovalResponseContent(
request.RequestId, // จับคู่กับคำขอเดิม
approved: humanSaidYes, // ผลจากมนุษย์จริง ไม่ใช่จาก model
request.ToolCall); // tool call เดิมที่รอ
messages.Add(new ChatMessage(ChatRole.User, [decision])); // ToolApprovalResponseContent : InputResponseContent → เป็นคำตอบของ "ผู้ใช้" ต่อคำขออนุมัติ จึงพกด้วย role User (ยืนยัน role กับ version Microsoft.Extensions.AI ที่ pin ไว้)
// ส่ง history กลับเข้า loop → FunctionInvokingChatClient รันต่อ:
// approved:true → เรียก IssueRefund จริง
// approved:false → ข้าม ไม่เรียก
caveat สอง​ข้อ​ที่​ถ้า​พลาด คุณ​จะ ship gate ปลอม

(1) ApprovalRequiredAIFunction แค่ mark — มัน ไม่ บังคับ เอกสาร Microsoft พูดตรงๆ (S31, verbatim): “It does not enforce the requirement for user approval; it is the responsibility of the invoker to obtain that approval.” ด่าน​เป็น​ของ​จริง ก็​ต่อ​เมื่อ สอง​อย่าง​ครบ: FunctionInvokingChatClient เคารพ marker (คาย​คำขอ​แทนที่​จะ​รัน) และ app ของ​คุณ block รอมนุษย์จริงๆ ถ้า app เห็น ToolApprovalRequestContent แล้ว auto-approve เอง คุณ​ก็ได้ gate ที่​ไม่​กัน​อะไร​เลย

(2) approval “stickiness” — เอกสาร FunctionInvokingChatClient เตือน​ไว้ (S30, verbatim): “if any FunctionCallContent is received for a function that requires approval, all received FunctionCallContent in that same response will also require approval, even if they were not ApprovalRequiredAIFunction instances.” แปล​ว่า​ถ้า model ขอ​เรียก​หลาย tool ใน​เทิร์น​เดียว​และ​มี​ตัว​หนึ่ง​ต้อง​อนุมัติ ทุก​ตัว ใน​เทิร์น​นั้น​จะ​ติด flag อนุมัติ​ไป​ด้วย ทาง​กัน: ตั้ง ChatOptions.AllowMultipleToolCalls = false เพื่อ​บังคับ​ให้​หนึ่ง​เทิร์นขอ​ได้ที​ละ tool

native surface สะดวก แต่​ทุก​วิศวกร​ควร​รู้​ว่า​มัน​ทำ​อะไร​ข้าง​ใต้ — และ​เมื่อ​คุณ​ไม่​ได้​อยู่​บน FunctionInvokingChatClient (เช่น hand-rolled loop ของ #15 บท6) คุณ​ต้อง​ทำ​เอง: ลง​ทะเบียน issueRefund เป็น declaration อย่าง​เดียว (ไม่ invocable) เพื่อ​ให้ loop ส่ง FunctionCallContent กลับ​มา​แทนที่​จะ​รัน แล้ว คุณ ตรวจ call นั้น ขอ​มนุษย์​ยืนยัน out-of-band รัน side effect จริง​เอง แล้ว​ป้อน FunctionResultContent กลับ — คุม​ได้​มากกว่า แต่ boilerplate เยอะ​กว่า รูป​นี้​แบก shape เดิม​ของ hand-rolled loop จาก #15/#17 มาตรงๆ

ต่อ​ให้​มี​ด่าน​อนุมัติ ก็​ยัง​มี​กับดัก​หนึ่ง​ที่​ทำให้ gate เปล่า​ประโยชน์ — Confused DeputyConfused Deputyagent ถูก​หลอก​ให้​ใช้ authority ของ​มัน​ทำ​สิ่ง​ที่​ผู้​โจมตี​ต้องการ — 'การ​ตัดสิน​ใจ​เรียก' issueRefund ของ model 'ไม่​เคย' เป็น​ขอบเขต authorization; authz ต้อง​อยู่​ใน tool handler (complete mediation): 'caller คน​นี้​ได้​รับ​อนุญาต​ให้ refund order นี้ ใน​วงเงิน​นี้ ให้​ลูกค้า​คน​นี้​ไหม' เช็ค​ซ้ำ​ใน code #14 สอน confused deputy ที่ tool-server boundary — นี่​คือ corollary ระดับ agentProcess คือ​สภาพ​ที่ agent (ผู้​มี​สิทธิ์) ถูก​หลอก​ให้​ใช้​สิทธิ์​นั้น​แทน​ผู้​โจมตี การ​ที่ model ตัดสิน​ใจ​เรียก issueRefund ไม่​เคย​เป็น​เส้น​แบ่ง authorization — ถ้า​คุณ​เชื่อ​การ​ตัดสิน​ใจ​ของ model ว่า​เป็นการ​อนุญาต injection ที่​ลอด​เข้า​มา​ก็​สั่ง​คืน​เงิน​ได้​ทันที OWASP LLM06 วาง​กฎ​นี้​ว่า complete mediation (S6, verbatim):

“Implement authorization in downstream systems rather than relying on an LLM to decide if an action is allowed.”

authorization ต้อง​อยู่​ใน handler ของ tool ไม่ใช่​ใน​หัว model — ภายใน IssueRefund ตัว​จริง ตรวจ​ซ้ำ​ใน code ใน​บริบท​ของ ผู้​ใช้​คน​นี้: caller คน​นี้​มี​สิทธิ์​คืน​เงิน​ออเดอร์​นี้​ไหม? ยอด ≤ cap ไหม? ออเดอร์​นี้​เป็น​ของ customer คน​นี้​จริง​ไหม? — ตรวจ​ใหม่​ทั้งหมด ไม่​ว่า model จะ​ตัดสิน​ใจ​อะไร #14 สอน confused deputy ที่​ขอบ tool-server; บท​นี้​คือ corollary ระดับ agent: marker ของ gate กับ​การ​ตรวจ authz ใน handler เป็น สอง​ชั้น ไม่มี​ชั้น​ไหน​ชั้น​เดียว​พอ

Blast RadiusBlast Radiusขอบเขต​ความ​เสียหาย​เมื่อ​การ​โจมตี 'ลอด' detection สำเร็จ — least privilege + approval gate + refund cap + rate limit + idempotency key (reuse #17 เป็น adversarial containment) ทำให้ loop ที่​ถูก hijack ยิง refund ซ้ำ​หรือ​เกิน​วงเงิน​ไม่​ได้ OWASP พูด​ตรง ๆ ว่า​มาตรการ​เหล่า​นี้ 'will not prevent Excessive Agency, but can limit the level of damage caused' — การ​หด blast radius เมื่อ detection พัง​คือ​หัวใจ​ของ containmentArchitecture คือ ขอบเขต​ความ​เสียหาย เมื่อ action หลุด​ออก​ไป — และ containment คือ​ศิลปะ​ของ​การ​ทำให้​มัน​เล็ก OWASP LLM06 ซื่อสัตย์​ตรง​จุด​นี้​มาก มัน​บอกว่า logging กับ rate-limiting (S6, verbatim):

“will not prevent Excessive Agency, but can limit the level of damage caused.”

“will not prevent … but can limit” — นี่​คือ honesty spine ของ​ทั้ง​คอร์ส​ใน​ประโยค​เดียว containment ไม่ หยุด injection แต่​มัน หด ความ​เสียหาย 3 primitive ที่​ประกอบ​เข้า​ด้วย​กัน:

  • refund cap ฝั่ง server — ยอด​คืน​ต่อ​ครั้ง/ต่อ session มี​เพดาน​ตายตัว​ใน code handler injection สั่ง​คืน 999,999 ไม่​ได้​ถ้า cap คือ​ยอด​ออเดอร์
  • rate limit — OWASP บอกตรงๆ (S6, verbatim): “Implement rate-limiting to reduce the number of undesirable actions that can take place within a given time period.” loop ที่​ถูก hijack ยิง​คืน​เงินรัวๆ ไม่​ได้​ถ้า​จำกัด N ครั้ง​ต่อ​หน้าต่าง​เวลา
  • idempotency key ของ #17 — reuse ตรงๆ แต่​เปลี่ยน threat model: #17 ใช้​มัน​กัน ดับเบิล​คลิก​โดย​บังเอิญ; บท​นี้​ใช้​มัน​กัน replay โดย​เจตนา — ผู้​โจมตี​ที่​ยิง​คำขอ​เดิม​ซ้ำๆ ได้​ผล​แค่​ครั้ง​เดียว​ถ้า handler เป็น idempotent primitive ความ​ทนทาน​จาก #17 กลาย​เป็น adversarial containment โดย​ไม่​ต้อง​เขียน​ใหม่

Anthropic วาง​เรื่อง​เดียวกัน​ใน​ภาษา​ของ agent loop — pause เพื่อ​ให้​มนุษย์​เข้า​มา​ที่ checkpoint และ​ตั้ง​เงื่อนไข​หยุด​เพื่อ​คุม loop (S16, verbatim): “Agents can then pause for human feedback at checkpoints or when encountering blockers.” และ “It’s also common to include stopping conditions (such as a maximum number of iterations) to maintain control.”

มี​ความ​จริง​เชิง​มนุษย์​ที่​ต้อง​สอน ไม่​งั้น​คุณ​จะ​ออกแบบ gate ที่​พัง— ยิ่ง​ขึ้น prompt อนุมัติ​บ่อย คน​ยิ่ง​กด​ผ่าน​โดย​ไม่​อ่าน Anthropic เปิด telemetry ของ Claude Code เอง​ว่า​ผู้​ใช้​กด​อนุมัติ prompt ราว ~93% (S17) ถ้า agent เด้ง prompt ทุก​ครั้ง​ที่​จะ​อ่านออเดอร์ มนุษย์​จะ​เรียนรู้​ที่​จะ​กด “yes” อัตโนมัติ แล้ว​พอ prompt ที่​สำคัญ​จริง (คืน​เงิน​ก้อน​ใหญ่) โผล่​มา มัน​ก็​ถูก rubber-stamp ไป​ด้วย

บทเรียน​ออกแบบ: gate เฉพาะ action ที่ impact สูง/ย้อน​คืน​ไม่​ได้ (issueRefund) — ไม่ใช่ ทุก read (getOrder / getDeliveryStatus ไม่​ต้อง​ผ่าน gate เพราะ​เป็น read-only รัน​ซ้ำ​ได้​ไม่​เจ็บ) gate ที่​ดัก​ทุก​อย่าง​คือ gate ที่​ไม่มี​ใคร​อ่าน — คือ gate ปลอม นี่​คือ​เหตุผล​ที่ EU AI Act Art. 14 พูด​ถึง human oversight ที่ มี​ประสิทธิผล​จริง และ​เตือน​เรื่อง automation bias (S22) — ด่าน​มนุษย์​ที่​คน​กด​ผ่าน​อัตโนมัติ ไม่ใช่ oversight

🔁 บท​นี้​อยู่​ตรง​ไหน​ใน​คอร์ส (anti-overlap)
  • vs #17 (robustness) — idempotency key ตัว​เดียวกัน แต่ threat model ตรง​ข้าม: #17 กัน ดับเบิล​คลิก​โดย​บังเอิญ; บท​นี้​กัน replay โดย​เจตนา reuse code ไม่ reuse สมมติฐาน
  • vs #14 (designing MCP servers) — #14 บังคับ authz ที่​ขอบ protocol MCP / tool-server; บท​นี้​บังคับ authz ใน handler ของ agent เอง (complete mediation) ที่​ต้อง​ยืน​ได้​แม้ tool/server เชื่อถือ​ได้​เต็ม​ร้อย
  • vs #13 (evals) — บท​นี้ หด ความ​เสียหาย ไม่ วัด พฤติกรรม การ​นับ​ว่า gate โดน bypass กี่​ครั้ง​คือ eval ของ #13 ส่ง​เคส​ไป​ให้ harness นั้น​วัด อย่า​สอน scoring ซ้ำ

แผนภาพ: least privilege + ด่าน​อนุมัติ​บน tool ที่​มี​ผล​ข้าง​เคียง

หัวข้อ​ที่​มีชื่อ​ว่า “แผนภาพ: least privilege + ด่าน​อนุมัติ​บน tool ที่​มี​ผล​ข้าง​เคียง”
flowchart TD
  ADV["injection ที่ลอดบท4/5<br/>สั่ง agent ให้คืนเงิน"] --> LOOP["loop agent<br/>FunctionInvocation"]

  subgraph TOOLS["least privilege — tool ที่ model เห็น"]
    R1["getOrder<br/>read-only · ไม่ผ่าน gate"]
    R2["getDeliveryStatus<br/>read-only · ไม่ผ่าน gate"]
    W["issueRefund<br/>write · mark ApprovalRequired"]
  end
  LOOP --> R1
  LOOP --> R2
  LOOP --> W

  W --> REQ["loop หยุด · คายคำขอ<br/>ToolApprovalRequestContent"]
  REQ --> HUMAN{"มนุษย์อนุมัติ?"}
  HUMAN -->|"no"| SKIP["ข้าม · ไม่คืนเงิน"]
  HUMAN -->|"yes"| AUTHZ["handler ตรวจ authz ซ้ำ<br/>caller · cap · idempotency"]
  AUTHZ -->|"ผ่านทุกด่าน"| DO["คืนเงินจริง<br/>ภายใน blast radius"]
  AUTHZ -->|"เกิน cap หรือไม่มีสิทธิ์"| DENY["ปฏิเสธใน code"]

  classDef danger fill:#b91c1c,stroke:#7f1d1d,color:#f8fafc;
  classDef guard fill:#475569,stroke:#1e293b,color:#f8fafc;
  class ADV,W danger;
  class REQ,HUMAN,AUTHZ guard;

คำ​บรรยาย​ภาพ: injection ที่​ลอด detection ของ​บท4/5 เข้า​มา​สั่ง​คืน​เงิน — แต่ containment สาม​ชั้น​หด blast radius: (1) least privilege — model เห็น​แค่ tool ที่​งาน​ต้อง​ใช้ และ issueRefund ถูก mark ว่า​ต้อง​อนุมัติ (2) ด่าน​มนุษย์ — loop หยุด​คาย​คำขอ ไม่​รัน​คืน​เงิน​เอง (3) complete mediation — handler ตรวจ authz + cap + idempotency ซ้ำ​ใน code ไม่​ว่า model หรือ​มนุษย์​จะ​ตัดสิน​ใจ​อะไร ไม่มี​ชั้น​ไหน​ชั้น​เดียว “แก้” injection ได้ แต่​ซ้อน​กัน​แล้ว​ทำให้​ความ​เสียหาย​ที่​เหลือ​อยู่​ใน​กรอบ

บท4/5 พยายาม จับ injection และ​จับ​ได้​ไม่​หมด บท​นี้​จึง​ถาม​คำถาม​ที่​ตาม​มา: เมื่อ​มัน​ลอด ความ​เสียหาย​จะ​เล็ก​แค่​ไหน? คำ​ตอบ​คือ excessive agency (LLM06) — ตัด functionality/permissions/autonomy ให้​เหลือ​เท่า​งาน​ด้วย least privilege, คร่อม issueRefund ด้วย native approval gate (ApprovalRequiredAIFunctionToolApprovalRequestContentToolApprovalResponseContent) ที่​เป็น​ของ​จริง​ก็​ต่อ​เมื่อ invoker block รอ​มนุษย์​จริง, วาง authz ใน handler ไม่ใช่​ใน​หัว model (กัน confused deputy), และ reuse idempotency + refund cap + rate limit ของ #17 เป็น adversarial containment — พร้อม​ความ​จริง​ว่า gate ที่​ดัก​ทุก​อย่าง​จะ​ถูก rubber-stamp (~93%) จน​กลาย​เป็น gate ปลอม บท​หน้า​เรา​ไป​ที่​ภัย​ของ​การ ดูด​ข้อมูล​ออก — data exfiltration และ system prompt leakage

ความ​ปลอดภัย​คือ​กระบวนการ ไม่ใช่ checkbox — least privilege + approval + cap ไม่​ได้​หยุด injection มัน​หด blast radius เมื่อ detection พลาด OWASP พูดไว้ตรงๆ ว่า control เหล่า​นี้ “will not prevent Excessive Agency, but can limit the level of damage caused” — containment นั่น​คือ​คือ​ประเด็น


🔗 อ้างอิง​ต้นทาง​ของ​บท​นี้

บท​นี้​อิง​ต้นทาง​ที่​ลง​วัน​ที่​กำกับ อ่าน​ต่อ​ได้​โดยตรง:

เช็กความเข้าใจ — บทที่ 6

ข้อ 1 / 3

ทำไม `ApprovalRequiredAIFunction` เพียงตัวเดียวถึงยัง *ไม่* ทำให้ approval gate เป็นของจริง?