如何製作讓AI安全使用WP-CLI的受限制指令包裝器

描繪一道門篩選旅宿經營者與AI對WordPress的操作,只讓安全操作通過的插畫 AI 網站管理

向AI交代「不要使用刪除指令」很重要,但光靠這段文字,無法保護正式網站。因為對委託的理解有誤、輸入錯誤,或後來追加的指示等,都可能讓AI選擇非預期的指令。

因此,我們不讓AI直接執行WP-CLI,而是在中間設置一個只接受少量、經管理者核准操作的入口。這個入口就是「受限制的指令包裝器」。

本文旨在解釋運作機制。導入前,請透過將WP-CLI交給AI之前的準備確認權限、備份與測試環境。變更伺服器使用者或權限的工作,應委託服務供應商或伺服器管理者處理。

什麼是受限制的指令包裝器

一般WP-CLI不只可查看文章,也有刪除、更新、資料庫操作與執行任意PHP程式碼等功能。官方指令列表中也包含wp db、wp eval、wp search-replace、wp user等需要謹慎處理的指令。

受限制的指令包裝器不會把AI輸入的字串直接傳給wp。例如,只接受以下三個自訂操作名稱。

  • site-status:確認WordPress的版本與狀態
  • plugin-status:確認外掛列表
  • post-list:確認已發布文章或草稿列表

包裝器內部將各項操作轉換成管理者已確認的WP-CLI指令。不符合的操作名稱會回傳錯誤,不予執行。

文字規則與技術限制的用途不同

在AGENTS.md或CLAUDE.md中,寫下「一開始只進行讀取」「發布、刪除與更新須經人核准」等作業規則,有助於AI與人共享判斷標準。

另一方面,受限制的指令包裝器會在執行路徑上阻擋未獲允許的操作。

旅宿經營者的委託
  ↓
Codex・Claude Code
  ↓
受限制的指令包裝器 ── 拒絕未獲允許的操作
  ↓
固定的WP-CLI指令
  ↓
WordPress

基本做法是結合文字規則、指令包裝器、OS與WordPress權限,以及人工確認。單靠一個包裝器,並不能保證安全。

安全設計原則

1. 從允許清單開始

不要只禁止危險指令,而應採用只允許已核准操作的方式。WP-CLI也有來自額外套件或外掛的指令,因此禁止清單可能漏掉未知操作。

一開始只確認狀態,再逐項新增有需要的操作。

2. 不直接接收WP-CLI指令字串

如果能向包裝器傳入像wp post list ...這樣的自由指令字串,檢查就容易出現漏洞。應接收post-list等自訂操作名稱,並在包裝器內固定實際指令與參數。

不得用eval重新執行輸入字串,也不得把整段輸入傳給shell。

3. 固定目標網站

WP-CLI有可變更目標的全域參數。不要讓外部自由傳入--path、--url、--ssh、--require、--exec等參數;WordPress位置與目標URL應由管理者固定。

4. 使用專用執行使用者

不要與AI共享平常的管理者帳號或root。應準備一個只具備確認WordPress所需權限的專用使用者,並移除互動式shell、檔案寫入與傳輸等不必要的權限。

即使指定WordPress使用者,也應限定為作業所需權限,而不是管理者權限。

5. 留下紀錄並限制數量

記錄執行日期與時間、操作名稱、成功或失敗,以及目標ID,但不在日誌中記錄文章正文、設定值或身分驗證資訊。每次執行的操作數量或取得的資料筆數,也應設定上限。

唯讀指令包裝器的最小範例

以下是用於說明機制的虛構環境範例,沒有包含實際WordPress位置或執行使用者。請勿直接放入正式環境;應由管理者依環境設計擁有者、權限、日誌與執行方式。

#!/usr/bin/env bash
set -euo pipefail

readonly PATH=/usr/local/bin:/usr/bin:/bin
readonly WP=/usr/local/bin/wp
readonly SITE=/srv/example/wordpress

action=${1:-}
shift || true

# 拒絕所有非預期的額外參數
if (( $# != 0 )); then
  echo "不可使用額外參數" >&2
  exit 64
fi

case "$action" in
  site-status)
    "$WP" --path="$SITE" core version
    "$WP" --path="$SITE" core is-installed
    ;;
  plugin-status)
    "$WP" --path="$SITE" plugin list \
      --fields=name,status,version --format=table
    ;;
  post-list)
    "$WP" --path="$SITE" post list \
      --post_type=post \
      --post_status=publish,draft \
      --fields=ID,post_title,post_status \
      --posts_per_page=20 \
      --format=table
    ;;
  *)
    echo "這項操作未獲允許" >&2
    exit 64
    ;;
esac

重點是不像wp "$@"那樣,把整段外部輸入交給WP-CLI。執行檔、WordPress位置、子指令與選項,都在包裝器端固定。

透過SSH時,也要固定入口

若讓AI透過SSH連線至VPS,應分開使用AI專用金鑰與使用者,並考慮採用連線後不允許開啟自由shell的設計。OpenSSH的ForceCommand能以固定指令取代用戶端指定的指令。

不過,單靠ForceCommand並不會阻止連接埠轉送或代理轉送。OpenSSH官方手冊也說明,不需要這些功能時,必須透過DisableForwarding等設定另外停用。

SSH設定有誤,可能讓管理者自己也無法連線。應保持現有連線,進行設定檢查與另一個工作階段的連線測試,並由網站製作公司或管理者設定。

允許建立草稿時的額外條件

讀取之後,若要允許製作文章,也不要開放自由使用wp post create,而應另設一個「建立一篇新文章草稿」的專用入口。

  • 將post_type固定為post
  • 將post_status固定為draft
  • 每次只處理一篇
  • 檢查slug的字元種類與長度
  • 將可讀取正文檔案的位置限制在專用目錄內
  • 從已核准的候選項目中選擇分類ID
  • 建立後回報文章ID與預覽位置
  • 將變更為publish的操作分成另外須經核准的程序

WP-CLI的wp post create可以指定文章狀態,因此能在包裝器端固定為draft。不過,即使是草稿,也可能儲存不適當的內容或個人資料。登錄後,務必由人在管理介面確認。

不應製作的指令包裝器

以下這類實作,即使名為「安全包裝器」,仍無法提供充分限制。

# 將任何外部輸入都傳給WP-CLI
wp "$@"

# 把字串再次當作shell解讀
eval "$SSH_ORIGINAL_COMMAND"

也應避免「沒有包含delete這個字就允許」之類的檢查方式,因為這會漏掉其他更新路徑、縮寫或額外指令。

導入前的確認清單

  • 執行使用者與管理者不同
  • 已核准操作名稱以外的名稱會回傳錯誤
  • 拒絕額外參數、未知選項與多筆操作
  • WP-CLI執行檔與WordPress位置已固定
  • 沒有使用eval或自由shell
  • 無法呼叫PHP執行、資料庫操作、設定顯示、更新或刪除
  • SSH的shell與各種轉送已受限制
  • AI端無法改寫包裝器與設定檔
  • 留有不包含秘密資訊的稽核日誌
  • 已在測試環境確認「允許」與「拒絕」兩種情況
  • 不只確認備份,也確認復原方法
  • 發布、更新與刪除,會停在由人核准的階段

給AI的委託範例

在這個網站,不要直接執行WP-CLI,只能使用管理者準備的
受限制指令包裝器。

請先確認可用的操作名稱,這次只使用唯讀的
site-status、plugin-status、post-list。

不要進行未獲允許的操作、使用額外參數、變更設定、更新、刪除或
發布。請回報已執行的操作名稱與結果,
不要在回答中顯示個人資料或秘密資訊。

這段委託文字是協助判斷的規則,應搭配執行路徑端的限制使用。

總結

讓AI協助使用WP-CLI時,不只要用文字禁止危險操作,也要準備一個只有已核准操作才能實際通過的入口。

一開始從大約三項唯讀操作開始,也要測試確實能拒絕操作。之後,再視需要逐項新增「建立一篇草稿」「確認公開頁面的HTTP回應」等專用操作。實際流程請見從備份到文章發布、HTTP與畫面確認的步驟。

若第一次接觸WP-CLI,請先閱讀什麼是WP-CLI?讓AI協助WordPress前應知道的基礎與安全入門。AI作業整體規則整理於使用AI管理WordPress的安全規則,文章列表請見給旅宿經營者的網站營運指南。

如何在實際運作中組合這些方法,並將失敗經驗納入規則,請見貓宿研究所的AI與WP-CLI運作案例。

參考資料

※伺服器、SSH與WordPress配置依服務供應商而異。修改設定前,請確認官方手冊與維護合約,並準備失去連線時的復原方法。

已複製標題與網址