SSD Nodes Learn RAM 8GB — $66/ปี
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-01

ป้องกันข้อมูลลับรั่วไหลจาก AI agent

API key ใน agent อาจรั่วไหลจากการเรียกใช้ tool เพียงครั้งเดียว เรียนรู้การใช้ scoped token อายุสั้นผ่าน credential gateway แทน key จริง

การไม่นำข้อมูลลับไปไว้ใน AI agents หมายถึงอะไร

AI agent คือกระบวนการ Linux ทั่วไปที่เรียกใช้คำสั่งได้ ตัวแปรสภาพแวดล้อมทุกตัวที่กระบวนการนั้นถืออยู่สามารถอ่านได้โดยโค้ดที่กระบวนการเรียกใช้ ดังนั้น API key ในสภาพแวดล้อมของ agent จึงเป็น key ที่ agent สามารถส่งไปยัง host ใดก็ได้ที่เข้าถึงได้ การไม่นำข้อมูลลับไปไว้ใน agent หมายถึงการมอบ handle ให้แทน key เช่น token ที่กำหนดขอบเขตและมีอายุสั้น หรือ placeholder ที่ระบบอื่นเปลี่ยนเป็นค่าจริงตรงขอบเขตเครือข่าย

นี่ไม่ใช่เรื่องของ model ที่กลายเป็นภัย กลไกนั้นเรียบง่ายกว่านั้น agent อ่านเว็บเพจ README หรือความคิดเห็นใน issue ที่มีคำสั่ง แล้วทำตาม เพราะสำหรับ language model ไม่มีความแตกต่างระหว่างข้อความที่คุณเขียนกับข้อความที่ดึงมา นี่คือ prompt injection เมื่อเกิดขึ้นแล้ว ขอบเขตความเสียหายขึ้นอยู่กับสิ่งเดียวอย่างชัดเจน นั่นคือกระบวนการสามารถอ่านอะไรได้บ้าง หากคุณยังไม่ได้กำหนดขอบเขต การเรียกใช้ coding agent อย่างปลอดภัยบน server จะอธิบายระดับการแยกสภาพแวดล้อมที่คู่มือนี้ต่อยอดอยู่บนพื้นฐานนั้น

รูปแบบภัยคุกคามโดยสรุป

เรียกใช้คำสั่งนี้ในฐานะผู้ใช้เดียวกับที่ agent ของคุณทำงาน

tr '\0' '\n' < /proc/self/environ | grep -iE 'key|token|secret|password'

ทุกบรรทัดที่คำสั่งนี้แสดงผลคือคำขอ HTTP หนึ่งรายการที่ส่งไปยัง server ของบุคคลภายนอก ตอนนี้ตรวจสอบข้อมูลที่อยู่บน disk ใกล้กับ agent

grep -rIl --exclude-dir=.git -e 'API_KEY' -e 'SECRET' ~/projects
find ~ -maxdepth 3 -name '.env' -o -name 'credentials' -o -name '*.pem'

agent ที่มี shell ไม่จำเป็นต้องใช้ช่องโหว่ที่ซับซ้อนเพื่อส่งข้อมูลดังกล่าวออกไป เส้นทางทั่วไป 4 รูปแบบก็เพียงพอ และทั้ง 4 รูปแบบจะดูเหมือนการทำงานปกติใน log:

  • curl หรือ fetch ขาออกไปยัง host ใดก็ได้ โดยใส่ค่าไว้ใน query string
  • git commit และ git push ไปยัง repository ที่ agent มีสิทธิ์เขียน
  • script สำหรับติดตั้ง package ซึ่งสามารถเรียกใช้ code ใดก็ได้ในฐานะผู้ใช้ของ agent
  • การค้นหา DNS ของ hostname ที่มีค่าอยู่ในชื่อ ซึ่งยังส่งข้อมูลออกไปได้แม้มีการบล็อก HTTP egress

คุณไม่สามารถแก้ปัญหานี้ได้ด้วยการตรวจสอบเพียงอย่างเดียว วิธีแก้คือทำให้แน่ใจว่าไม่มีข้อมูลสำคัญอยู่ในตำแหน่งที่เข้าถึงได้

ความลับใน working tree คือความลับใน context window

เอเจนต์จะอ่านไฟล์ โดยจะอ่านไฟล์ .env ที่อยู่ใน repository ซึ่งกำลังทำงานอยู่ และเมื่ออ่านแล้ว ไฟล์นั้นจะอยู่ใน context window ซึ่งหมายความว่าไฟล์นั้นจะอยู่ใน transcript ใน log ที่คุณเก็บไว้ และในสิ่งที่เอเจนต์เขียนต่อไป

ก่อนหน้านี้ เมื่อ key อยู่ใน tree ที่เอเจนต์กำลังทำงาน:

cd ~/projects/billing
cat .env
# STRIPE_SECRET_KEY=sk_live_...
# DATABASE_URL=postgres://app:hunter2@db.internal:5432/billing

หลังจากย้ายไฟล์ออกจากตำแหน่งที่เอเจนต์เข้าถึงได้:

sudo install -d -m 750 -o root -g agent-review /etc/agent-review
sudo install -m 640 -o root -g agent-review ~/projects/billing/.env /etc/agent-review/billing.env
rm ~/projects/billing/.env

ผู้ใช้ของเอเจนต์จะไม่สามารถเปิดไฟล์ได้อีก เนื่องจาก working tree ไม่มีไฟล์นั้นแล้ว กฎ deny ใน config ของเอเจนต์เป็นชั้นป้องกันที่สอง ไม่ใช่ชั้นแรก Claude Code จะอ่านกฎ permission จาก .claude/settings.json ใน project:

{
  "permissions": {
    "deny": ["Read(./.env)", "Read(./secrets/**)", "Read(./**/*.pem)"]
  }
}

การตั้งค่านี้ป้องกันไม่ให้เอเจนต์เปิดไฟล์โดยไม่ได้ตั้งใจขณะสำรวจ แต่ไม่ป้องกันคำสั่งที่ถูกแทรกให้รัน base64 .env เนื่องจากคำสั่งดังกล่าวเป็น shell command ไม่ใช่การอ่านไฟล์ ให้ถือว่า config เป็นแนวป้องกัน และ filesystem permission เป็นกำแพง การแยกชั้นแบบเดียวกันนี้ใช้ภายใน container ด้วย: ไฟล์ env และ secret ใน Docker Compose อธิบายปัญหานี้ในระดับที่อยู่ลึกลงไปอีกหนึ่งชั้น

ให้ agent แต่ละตัวใช้ผู้ใช้ที่ไม่มีสิทธิ์ระดับสูงของตนเอง

หาก agent ทำงานในบัญชีของคุณ agent จะสืบทอด SSH keys, cloud credentials และประวัติ shell ของคุณ การสร้างผู้ใช้แยกใช้เพียงหนึ่งคำสั่งและจะตัดการเข้าถึงทั้งหมดนี้

sudo adduser --disabled-password --gecos "" agent-review
sudo chmod 700 /home/agent-review
sudo -u agent-review cat ~/.ssh/id_ed25519

บรรทัดสุดท้ายต้องล้มเหลวด้วย cat: /home/you/.ssh/id_ed25519: Permission denied หากคำสั่งแสดง key แทน แสดงว่าไดเรกทอรี home ของคุณอ่านได้โดยกลุ่มหรือผู้ใช้ทั่วไป และ chmod 700 ~ จะแก้ไขปัญหานี้ ห้ามเพิ่มผู้ใช้ของ agent ไปยัง sudo และห้ามกำหนดกฎ NOPASSWD ให้กว้างเกินกว่าคำสั่งเดียวที่จำเป็นต้องใช้จริง ผู้ใช้ที่มีสิทธิ์น้อยที่สุดบน VPS อธิบายรายละเอียดของกลุ่มและ sudoers

ควรเพิ่มขอบเขตอีกหนึ่งชั้นสำหรับ cloud VPS บริการ instance metadata จะตอบสนองที่ local address แบบ link ที่กำหนดตายตัว และมักแจกจ่าย role credentials ให้ทุกสิ่งที่ส่งคำขอ

sudo iptables -A OUTPUT -m owner --uid-owner agent-review -d 169.254.169.254 -j REJECT

ตรวจสอบจากฝั่งของ agent คำสั่ง sudo -u agent-review curl -s --max-time 3 http://169.254.169.254/ ต้องไม่แสดงผลลัพธ์ใดและต้องจบการทำงานด้วยสถานะที่ไม่ใช่ศูนย์ เนื่องจาก packet ถูกปฏิเสธก่อนออกจากเครื่อง

ฉีดข้อมูลรับรองที่ขอบเขต

รูปแบบที่แก้ปัญหานี้ได้จริงคือการฉีดข้อมูลรับรอง เอเจนต์จะไม่ถือคีย์จริง แต่จะส่งคำขอผ่านเกตเวย์ภายในเครื่อง แล้วเกตเวย์จะแทนที่ค่า placeholder ด้วยข้อมูลลับจริงก่อนส่งออก ข้อมูลลับจะอยู่ในพื้นที่จัดเก็บของเกตเวย์ ซึ่งทำงานในกระบวนการอื่นและอยู่ภายใต้ผู้ใช้อื่น

OneCLI เป็นการนำแนวทางนี้ไปใช้งานแบบโอเพนซอร์สหนึ่งรูปแบบ เผยแพร่ภายใต้สัญญาอนุญาต Apache-2.0 และทำงานเป็นคอนเทนเนอร์ที่อยู่ถัดจากเอเจนต์ ณ เดือน July 2026 โครงการระบุการตั้งค่าดังนี้:

git clone https://github.com/onecli/onecli.git
cd onecli
docker compose -f docker/docker-compose.yml up -d --wait

dashboard รับการเชื่อมต่อที่พอร์ต 10254 และ gateway รับการเชื่อมต่อที่พอร์ต 10255 คุณจัดเก็บข้อมูลรับรองจริงเพียงครั้งเดียว จากนั้นกำหนดค่า placeholder ให้เอเจนต์แต่ละตัวแทนคีย์ พร้อม access token ที่กำหนดขอบเขตเฉพาะของเอเจนต์นั้น ซึ่งเอเจนต์จะส่งในส่วนหัว Proxy-Authorization gateway จะจับคู่คำขอขาออกตาม host และ path ถอดรหัสข้อมูลรับรองที่ตรงกัน แล้วแทนที่ค่าให้ เอเจนต์จึงไม่มีข้อมูลใดใน environment ที่ผู้โจมตีจะนำไปใช้ได้

คุณค่าของแนวทางนี้ไม่ได้อยู่ที่การเข้ารหัส แต่อยู่ที่คำถามว่า “เอเจนต์นี้ใช้ข้อมูลใด และใช้เมื่อใด” กลายเป็นคำค้นหาใน log คุณอ่าน audit trail เพียงรายการเดียว แทนการคาดเดาว่าสภาพแวดล้อมใดจาก 6 สภาพแวดล้อมที่เก็บสำเนาคีย์ไว้

ส่งค่าลับให้กระบวนการ ไม่ใช่ให้ environment

หากเรียกใช้ agent ภายใต้ systemd คุณไม่จำเป็นต้องใช้ environment variables เลย LoadCredential= จะวางค่าลับไว้ในไดเรกทอรีส่วนตัวที่มีเฉพาะ service นั้นเท่านั้นที่อ่านได้ โดยแสดงเป็น %d ในไฟล์ unit และเป็น $CREDENTIALS_DIRECTORY ภายในกระบวนการ ค่าดังกล่าวจะไม่ปรากฏใน /proc/<pid>/environ ดังนั้น ps eww จึงไม่สามารถแสดงค่าได้ และไดเรกทอรีจะถูกลบเมื่อ service หยุดทำงาน

เข้ารหัส credential ให้กับเครื่องก่อน คำสั่งเหล่านี้มาจากเอกสาร systemd และใช้งานได้บน systemd 250 หรือใหม่กว่า ซึ่งครอบคลุม Ubuntu 24.04 และ Debian 13:

echo -n 'sk-example-value' > /tmp/plain.txt
sudo systemd-creds encrypt --name=api_key /tmp/plain.txt /etc/credstore/api_key.cred
shred -u /tmp/plain.txt
sudo systemd-run -P --wait -p LoadCredentialEncrypted=api_key:/etc/credstore/api_key.cred \
  systemd-creds cat api_key

คำสั่งสุดท้ายจะแสดง sk-example-value ซึ่งยืนยันว่าไฟล์ที่เข้ารหัสสามารถถอดรหัสบนโฮสต์นี้ได้ จากนั้นให้อ้างอิงไฟล์ดังกล่าวจาก unit:

[Service]
User=agent-review
LoadCredentialEncrypted=api_key:/etc/credstore/api_key.cred
Environment=AGENT_KEY_FILE=%d/api_key
ExecStart=/usr/local/bin/agent-worker

โค้ดของ agent จะเปิดไฟล์ที่ $AGENT_KEY_FILE เมื่อต้องการค่า การอ่านไฟล์เกิดขึ้นเพียงชั่วขณะ ส่วน environment variable จะคงอยู่ตลอดอายุของกระบวนการ รวมถึงในกระบวนการลูกทุกกระบวนการที่กระบวนการนั้นสร้างขึ้น

เลือกใช้โทเค็นอายุสั้นแทนคีย์อายุยาว

คีย์ที่ไม่มีวันหมดอายุยังคงใช้งานได้เมื่อปรากฏในภายหลัง ไม่ว่าจะเป็นใน log หรือบันทึกการทำงานหลังจากผ่านไปหลายเดือน หากบริการมี session token ให้ใช้ session token และกำหนดอายุการใช้งานให้สั้นที่สุดเท่าที่งานนั้นรองรับ

aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/agent-readonly \
  --role-session-name agent-review \
  --duration-seconds 900

AWS STS (security token service) ยอมรับระยะเวลาขั้นต่ำ 15 นาที ซึ่งโดยทั่วไปเพียงพอสำหรับงานของ agent 1 งาน สำหรับ GitHub ให้ผู้ใช้ของ agent มีบัญชีเข้าสู่ระบบ gh ของตนเอง พร้อม token แบบกำหนดขอบเขตละเอียดที่จำกัดให้ใช้ได้กับ repository เดียวที่ agent ทำงานอยู่ เพื่อให้ gh auth token ภายใน session นั้นส่งคืนข้อมูลที่ไม่สามารถเข้าถึงสิ่งอื่นได้ ให้กำหนดขอบเขตตาม resource ก่อน แล้วจึงกำหนดตามเวลา

ตรวจสอบ แล้วตรวจสอบซ้ำอย่างต่อเนื่อง

หลังจากเปลี่ยนแปลงการตั้งค่าของ agent แล้ว ควรเรียกใช้การตรวจสอบ 3 รายการ ตรวจสอบในฐานะผู้ใช้ของ agent ไม่ใช่ผู้ใช้ของคุณเอง

sudo -u agent-review env | grep -iE 'key|token|secret'
sudo -u agent-review ls -la /home/you/ 2>&1 | head -3
sudo -u agent-review curl -s -o /dev/null -w '%{http_code}\n' --max-time 5 https://api.github.com/user

รายการแรกควรไม่แสดงผลลัพธ์ใด ๆ รายการที่สองควรแสดง ls: cannot open directory '/home/you/': Permission denied รายการที่สามจะแสดงข้อมูลระบุตัวตนที่เส้นทางเครือข่ายของ agent นำเสนอ ซึ่งเป็นคำถามที่รูปแบบ gateway นี้มีไว้เพื่อตอบ: 401 หมายความว่า agent ไม่มีข้อมูลรับรอง GitHub ของตนเอง และ 200 หมายความว่า agent มีข้อมูลรับรองดังกล่าว ดังนั้นคุณควรทราบว่าเป็น token รายการใด หากคุณเรียกใช้ agents โดยไม่มีผู้ดูแล การควบคุมค่าใช้จ่ายของ AI agent บน VPS จะอธิบายขีดจำกัดงบประมาณที่ใช้ร่วมกับขีดจำกัดการเข้าถึงเหล่านี้

FAQ

ฉันสามารถเชื่อถือโมเดลไม่ให้เปิดเผยคีย์ของฉันได้หรือไม่

ไม่ได้ เพราะโมเดลไม่ใช่ผู้โจมตีในแบบจำลองภัยคุกคามนี้ Agent อ่านข้อความจากเว็บเพจ repository และระบบติดตาม issue และข้อความเหล่านั้นอาจมีคำสั่งแฝงอยู่ โมเดลไม่มีวิธีที่เชื่อถือได้ในการแยกคำสั่งของคุณออกจากข้อความที่ดึงมา การควบคุมใดก็ตามที่ขึ้นอยู่กับการที่โมเดลเลือกได้ถูกต้องจะล้มเหลวทันทีที่คำสั่งแทรกมีความน่าเชื่อถือ ดังนั้นการควบคุมต้องอยู่ในระบบปฏิบัติการหรือเครือข่ายแทน

ตัวแปรสภาพแวดล้อมเป็นปัญหาสำหรับข้อมูลลับของ Agent จริงหรือ

เป็นปัญหาในด้านหนึ่งโดยเฉพาะ คือ ตัวแปรเหล่านี้ถูกสืบทอด ทุก child process ที่ Agent สร้างขึ้นจะได้รับสำเนา รวมถึง build script, test runner และ hook สำหรับติดตั้ง package ตัวแปรเหล่านี้ยังอ่านได้ผ่าน /proc/<pid>/environ โดยผู้ใช้คนเดียวกัน ดังนั้นทุกสิ่งที่ Agent เรียกใช้จึงอ่านตัวแปรเหล่านี้ได้โดยไม่ต้องให้ Agent ส่งต่อ การอ่านไฟล์ในขณะที่ใช้งานด้วย LoadCredential= หรือผ่าน gateway จะจำกัดการเปิดเผยข้อมูลไว้เฉพาะช่วงเวลาดังกล่าว

การเก็บข้อมูลลับไว้ใน vault แก้ปัญหานี้ได้ด้วยตัวเองหรือไม่

แก้ได้เพียงบางส่วน vault ช่วยแก้ปัญหาการจัดเก็บ แต่ไม่ได้แก้ขั้นตอนสุดท้าย ซึ่งมีบางสิ่งดึงข้อมูลลับออกจาก vault แล้วส่งให้ Agent ในรูปตัวแปรสภาพแวดล้อม ทำให้กลับไปอยู่ในสถานการณ์เดิม สิ่งสำคัญคือผู้ใดเป็นผู้แทนค่าตัวแปร หาก Agent เป็นผู้ดึงข้อมูลลับ Agent ก็จะมีข้อมูลลับนั้น หาก gateway หรือระบบ init เป็นผู้แทนค่านอก process ของ Agent Agent ก็จะไม่ถือข้อมูลลับนั้นไว้

ฉันจะทราบได้อย่างไรว่า Agent เคยเปิดเผยข้อมูลบางอย่างไปแล้ว

โดยปกติจะไม่สามารถทราบย้อนหลังได้ ซึ่งเป็นเหตุผลที่ควรใช้ gateway หากไม่มี gateway หลักฐานจะกระจัดกระจายอยู่ในประวัติ shell, transcript ของ Agent และ log การเชื่อมต่อขาออกที่คุณอาจไม่ได้เก็บไว้ เมื่อสงสัยว่ามีข้อมูลรั่วไหล ให้หมุนเวียนคีย์ก่อน แล้วจึงตรวจสอบภายหลัง การหมุนเวียนคีย์มีต้นทุนต่ำ แต่ความแน่นอนไม่ได้มีต้นทุนต่ำเช่นนั้น

วันนี้ฉันควรทำอะไรเป็นอย่างน้อย

ย้ายไฟล์ .env ทั้งหมดออกจากไดเรกทอรีที่ Agent ใช้งาน และสร้างผู้ใช้ที่ไม่มีสิทธิ์พิเศษหนึ่งรายต่อ Agent การเปลี่ยนแปลง 2 อย่างนี้ใช้เวลาประมาณ 10 นาที และปิดช่องทางที่พบบ่อยที่สุด ซึ่งคือ Agent อ่านไฟล์ข้อมูลลับที่ไม่มีเหตุผลต้องวางไว้ใกล้โค้ด gateway และ token อายุสั้นเป็นขั้นตอนถัดไป ไม่ใช่ขั้นตอนแรก แนวทางเริ่มต้นเดียวกันนี้ใช้ได้กับ runtime ของ Agent ทุกประเภท รวมถึง การเรียกใช้ Agent อัตโนมัติอย่างปลอดภัยบน VPS