Skip to content

idd-edit:echo "$VAR" > file 在 zsh 下會把 LaTeX/反斜線內容當跳脫序列解讀,靜默損壞 dispatch 的 body #330

Description

@kiki830621

Problem

在實際使用 idd-issueidd-clarify 為一則含 LaTeX 數學公式的 issue(kiki830621/article1-polychoric-ordinal-sem-ifa-identifiability#1)做多輪 body 編輯時,發現 GitHub 上的 issue body 被靜默損壞:\Sigma_\nu\equiv 這類 LaTeX 反斜線序列,被轉成真正的換行字元與 ESC (0x1B) 控制字元。不是 gh CLI 的問題,是 zsh 的 echo builtin 預設會解讀反斜線跳脫序列(等同 bash 的 echo -e,跟 bash 的 echo 預設行為不同)。

已在自己的 session 裡定位到根因並用 Python 重寫該則 issue 修復,但同一個寫法(echo "$VAR" > file 後續接 --body-file dispatch)在 idd-edit skill 的官方參考程式碼裡也有兩處一模一樣的寫法,任何 zsh 使用者只要編輯的內容含 LaTeX 或其他「反斜線+單一字母剛好是 C-style escape」的文字,都會踩到同一個坑。

Type

bug

根因(已用最小重現案例驗證,非猜測)

# 在 zsh 裡執行:
TEST_VAR='hello\nworld\eEND'
echo "$TEST_VAR" | od -c
# 結果:\n 被轉成真正的換行、\e 被轉成 ESC(033) 控制字元
#   h e l l o \n(真換行) w o r l d ESC E N D

printf '%s' "$TEST_VAR" | od -c
# 結果:逐字保留,backslash n w o r l d backslash e E N D(正確)

zsh 的 echo builtin(不加任何 flag)預設就是 echo -e 語意;bash 的 echo 預設不是。這個 plugin 的使用者環境不保證是 bash——Bash 這個 harness tool 名稱容易讓人誤以為底層一定是 bash,但實際上很多使用者(包含我)的預設互動 shell 是 zsh。

受影響的確切位置(已逐一 grep 確認,全 repo 只有這兩處符合 echo "$VAR" > "$FILE" 這個 pattern)

skills/idd-edit/SKILL.md

310:    echo "$BODY_INPUT" > "$REPL_FILE"
376:echo "$NEW_BODY" > "$TMP_BODY_FILE"

第 310 行:$BODY_INPUT(使用者想替換進去的新內容)寫進 $REPL_FILE,接著餵給 idd-edit-helper.py section-replace 做 named-section 替換——如果 $BODY_INPUT 含 LaTeX,替換結果從這一步就已經壞了。

已延伸掃描其他可能變體(無空白分隔、未加雙引號、多變數內插等形式),確認沒有其他「把內容寫進檔案供後續 dispatch」的同類實例——其餘命中的 echo "...文字 $VAR..." >&2 全部是印給人看的 log/錯誤訊息,不是要寫檔或送出的內容,不構成同一類風險。

第 376 行更直接:緊接著在同一段程式碼裡就是

echo "$NEW_BODY" > "$TMP_BODY_FILE"
...
bash "$CLAUDE_PLUGIN_ROOT/scripts/gh-egress.sh" edit-comment "$COMMENT_ID" \
    --repo "$REPO" --body-file "$TMP_BODY_FILE" --scrub-attested "$SCRUB_LEVEL"

這跟我在自己 session 裡踩到、重現的失敗模式完全同構:先把 body 內容寫進暫存檔,再用 --body-file 派送。在 zsh 下,$NEW_BODY 只要含 \n\t\b\a\f\v\e\r 這幾種 2-字元序列(剛好對應到大量常見 LaTeX 巨集的字首:\nu\tau\beta\alpha\forall\vee\equiv\rho 等),對應的兩個字元就會被解讀成真正的控制字元,靜默寫進 dispatch 的 body-file,gh-egress.sh 的既有防護網(--scrub-attested 語意隱私自審、mention 偵測等)完全不會攔這種機械性資料毀損,因為它們檢查的是內容語意,不是位元完整性。

為什麼不是 gh-egress.shgh CLI 的問題(已排除)

用完全相同的乾淨檔案分別測過:

  1. 原生 gh issue edit --body-file <乾淨檔>(不經過 wrapper)→ 結果正確
  2. 經過 gh-egress.sh edit --body-file <乾淨檔>(有 wrapper)→ 結果也正確
  3. 唯獨 echo "$VAR" > file(zsh)產生的檔案本身就已經壞了,餵給誰都一樣壞

gh-egress.sh 本身透過 "${GH_ARGS[@]}" 陣列展開傳遞參數,過程不涉及任何 echo/printf 重新序列化,是乾淨的。

Expected

任何把 body/comment 內容寫進暫存檔供後續 --body-file dispatch 的地方,都應該逐位元保留輸入,不因為內容剛好長得像某種 shell escape 序列而被改寫。

Actual

skills/idd-edit/SKILL.md 第 310、376 行用 echo "$VAR" > file,在 zsh 環境下對含特定反斜線序列的內容(LaTeX 是最常見的觸發源)造成靜默資料毀損:真實換行與 ESC 控制字元混入本該是純文字的 GitHub issue/comment body。

Impact

  • 任何統計/數學/物理背景的使用者,只要編輯的 issue 或 comment 含 LaTeX 數學符號(\nu\beta\alpha\tau\forall\vee\equiv 等以 n t b a f v e r 開頭的巨集),在 zsh 下用 idd-edit 的 named-section replace 或 comment 編輯路徑,都會靜默壞掉,且沒有任何錯誤訊息——gh-egress.sh 的隱私自審與機械 net 都不會攔這種位元層級的毀損。
  • 已知受害案例:kiki830621/article1-polychoric-ordinal-sem-ifa-identifiability#1(本人 session 內,已自行修復)。
  • 由於是靜默失效,過去是否已有其他使用者在不知情的狀況下產生過壞掉的 issue body,無從得知——這正是這類 bug 最危險的地方。

建議修法(供 fix 時參考,非強制)

兩處 echo "$VAR" > "$FILE" 改成 printf '%s' "$VAR" > "$FILE"printf %s 對參數值不做任何跳脫解讀,逐位元保留)即可修好這兩個已知位置。

但這是同一類問題在整個 plugin 裡的其中兩個實例,不代表窮盡了所有風險——建議把「shell script 裡任何把使用者/GitHub 內容寫進檔案或送進管線」的地方都盤點一次,確認一律用 printf '%s' 而不是 echoprintf 的 format string 用單引號固定字面 '%s',值本身一律當資料、不重新解析)。另外也可以在 IDD 通用開發規範裡加一條「shell script 一律假設在 zsh 下執行(Bash harness tool 的底層不保證是 bash),不可依賴 bash-only 的 echo 語意」——這類坑很可能還有其他實例沒被踩到。

Clarity Surface(idd-clarify run 2026-09-05T01:58:00Z)

Type Source Question for you Status
(none) no issues detected passed

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions