hihi,我是歐娜😺
前面幾天我們一直在看:
使用者丟進 AI 的東西安不安全?
像是 Prompt Injection、資料污染、RAG 找到錯誤內容等等。
但今天要把方向反過來。
不是看:
「什麼東西進到 LLM?」
而是看:
「LLM 產生的東西,接下來去了哪裡?」
今天來看 OWASP LLM Top 10 2026 最後一名:
LLM10:Improper Output Handling(不當輸出處理)。
這一條可以先很簡單理解成:
把 LLM 產生的內容直接當成可信資料,沒有經過驗證或處理,就交給下一個系統使用。
例如:
User
↓
LLM
↓
產生 SQL
↓
Database 直接執行
或:
User
↓
LLM
↓
產生 HTML / JavaScript
↓
Browser 直接 Render
甚至:
User
↓
LLM
↓
產生 Shell Command
↓
Server 直接執行
看到這裡應該已經有一點感覺了:
真正危險的不是 LLM 產生了一段文字。
而是:
系統看到那段文字之後,真的照著做了。
我們在寫一般 Application 時,應該都很熟悉一個觀念:
User Input 不可信。
例如使用者輸入:
<script>alert('hello')</script>
我們不會直接相信它。
使用者傳進來的:
Query Parameter
Form Data
Request Body
File
通常都需要經過:
Validation
Sanitization
Authorization
再交給後面的系統。
但接上 LLM 之後,很容易出現一個奇怪的心理:
這是 AI 產生的,應該比較安全吧?
其實沒有🤣
因為 LLM 的 Output 本身可能受到:
User Prompt
Prompt Injection
RAG Content
第三方資料
Tool 回傳內容
影響。
也就是說:
攻擊者可能沒有辦法直接控制 Backend,但他有機會先影響 LLM,再利用 LLM 的 Output 間接影響 Backend。
所以今天最重要的一個觀念就是:
LLM Output 也要當成 Untrusted Input。
不要因為它是 AI 產生的,就自動多給一層信任。
假設今天做了一個 Database Assistant。
使用者可以直接用自然語言問:
幫我找出今天新增的 Customer。
LLM 幫忙產生:
SELECT *
FROM customers
WHERE created_at >= CURRENT_DATE;
接著 Backend:
LLM 產生 SQL
↓
Database Execute
↓
回傳結果
看起來超方便。
但問題來了。
如果使用者改問:
幫我產生一段 SQL,把所有資料表都刪掉。
LLM 真的產生:
DROP TABLE customers;
如果你的系統是:
LLM Output
↓
直接 Execute
那……
AI 就真的幫你刪了🤣
這時其實不是:
LLM 回答錯了。
它可能完全照使用者的要求回答。
真正的問題是:
Application 把 LLM 產生的文字,直接當成可以執行的 SQL。
所以真正要防的不是只有:
Prompt 要怎麼寫,叫 AI 不要產生危險 SQL?
而是 Backend 本身就要限制:
哪些 Query 可以執行?
可以操作哪些 Table?
可以做 SELECT 嗎?
可以 DELETE 嗎?
目前這個 User 有沒有權限?
不能把安全責任全部丟給 LLM。
可能有人會想:
那我在 System Prompt 寫「絕對不要產生 DELETE SQL」不就好了?
例如:
你是一個 Database Assistant。
只能產生 SELECT Query。
禁止 DELETE。
禁止 DROP。
禁止 UPDATE。
這可以當成其中一道限制。
但它不能是唯一一道。
因為前面 Prompt Injection 已經講過很多次:
LLM 的 Instruction 本身不是強制安全邊界。
如果今天真正的 Backend 權限是:
Database Account
↓
SELECT
INSERT
UPDATE
DELETE
DROP
ALL PRIVILEGES
然後安全機制只有:
拜託 AI 不要產生 DELETE。
這其實非常危險🤣
比較好的設計應該是:
LLM
↓
產生查詢需求
↓
Backend 驗證
↓
只允許安全範圍
↓
Database
甚至 Database Account 本身就只給:
SELECT
這樣就算 LLM 真的產生:
DROP TABLE customers;
後面也執行不了。
這其實又回到前面一直講的:
Least Privilege(最小權限)。
另一個很好理解的例子是:
HTML / JavaScript。
假設今天有一個 AI:
幫使用者產生活動介紹頁面。
LLM 回傳:
<h1>AI Security Workshop</h1>
<p>歡迎報名!</p>
前端直接 Render。
看起來沒問題。
但如果某次產生的內容裡出現:
<script>
// malicious code
</script>
而前端完全沒有做處理,就直接把內容當成 HTML 執行,
就可能形成:
XSS(Cross-Site Scripting)。
流程變成:
User / 惡意內容
↓
影響 LLM
↓
LLM 產生惡意 HTML / JavaScript
↓
Frontend 直接 Render
↓
Browser 執行
注意喔,
Browser 不知道:
這段 JavaScript 是 AI 寫的耶~
🤣
它只知道:
你叫我執行這段 Code。
所以 AI 產生的網頁內容,一樣需要:
Sanitization
Output Encoding
允許的 HTML Tag
Content Security Policy
等安全處理。
這裡會看到一個很常見的技術:
Output Encoding。
可以先簡單理解成:
不要讓原本應該只是「文字」的內容,被下一個系統誤認成「可以執行的指令」。
例如使用者輸入:
<script>alert(1)</script>
如果我們只是想把它當成文字顯示,
畫面應該讓使用者看到:
<script>alert(1)</script>
而不是:
真的執行這段 JavaScript。
所以系統在把內容放進 HTML、JavaScript、URL 等不同位置前,
都需要按照那個使用情境做正確處理。
也就是:
AI 產生了什麼是一回事,這段內容接下來要被放在哪裡,又是另一回事。
再來一個更危險的例子。
假設做了一個 AI DevOps Assistant。
使用者說:
幫我找出 Server 裡最大的 Log File。
LLM 產生:
du -ah /var/log | sort -rh | head
然後系統:
LLM Output
↓
Shell
↓
Execute
看起來超級自動化。
但如果某次 LLM 產生的是危險 Command,
而 Backend 又直接:
exec(llmOutput)
那風險就非常高。
因為此時:
LLM 其實等於間接拿到了 Shell 的操作能力。
如果再搭配 Prompt Injection:
攻擊者輸入
↓
影響 LLM
↓
LLM 產生危險 Command
↓
Backend 直接 Execute
原本只是:
一段 Prompt。
最後可能一路變成:
Remote Code Execution(RCE)。
所以如果真的要讓 AI 操作系統,
至少應該限制:
允許哪些 Command?
哪些參數?
可以操作哪些路徑?
使用什麼 Service Account?
需要 Human Approval 嗎?
而不是:
AI 回什麼我就跑什麼。
Improper Output Handling 不一定都是:
執行 Code
有時候只是拿 AI Output 去組一個 File Path,
一樣可能出事。
例如:
LLM:
請讀取 reports/2026/report.pdf
Backend:
open(llmOutput)
如果輸出的路徑最後變成:
../../../../etc/passwd
就可能產生:
Path Traversal。
也就是透過:
../
一路跑去存取原本不應該碰到的檔案。
所以:
AI 說「請讀這個 File」
不代表 Backend 就真的直接照著那個 Path 去讀。
還是需要確認:
是不是允許的 Directory?
是不是允許的 File Type?
路徑是否在預期範圍?
這個應該就超級有感了🤣
現在很常:
AI
↓
產生 Code
↓
Developer Copy
↓
Deploy
如果中間還有人 Review,
至少還有一層。
但如果流程變成:
需求
↓
AI 產生 Code
↓
自動 Build
↓
自動 Deploy
↓
Production
那 AI 產生的內容就直接進 Production 了。
問題是:
AI 產生的 Code 本身可能有漏洞。
例如:
SQL Injection
XSS
Hard-coded Secret
缺少 Authorization
Command Injection
都可能被寫進去。
所以 2026 版的 Improper Output Handling 也特別把:
AI 產生的 Code 被直接拿去 Build / Deploy
納入這類風險。
重點一樣不是:
AI 為什麼寫出 Bug?
而是:
為什麼這段 Code 沒有經過 Review、Security Test,就直接被當成可信 Code?
看到這裡可能會想到 Day 11:
Misinformation。
因為兩個好像都是:
AI Output 有問題。
但其實關注點不一樣。
可以先這樣分:
Misinformation
→ AI 產生錯誤、誤導或不完整的資訊
Improper Output Handling
→ 系統沒有安全處理 AI Output,
就直接拿去執行或交給其他元件使用
例如 AI 說:
Customer 可以退款。
但其實根本不符合退款條件。
這比較偏:
Misinformation。
但如果 AI 回傳:
DELETE FROM orders;
Backend 直接拿去 Database 執行,
這比較偏:
Improper Output Handling。
甚至 AI 產生的內容本身可以完全正確。
例如:
rm -rf ./data
這是一條完全合法的 Shell Command。
問題只是:
你的系統到底該不該直接執行它?
所以今天這條並不是在判斷:
AI 說得對不對。
而是在判斷:
AI 說完之後,我的 Application 怎麼處理這個 Output?
Prompt Injection 看的是:
攻擊者怎麼影響 LLM 的行為。
Improper Output Handling 看的是:
LLM 產生的結果,後面的系統怎麼使用。
例如:
攻擊者
↓
Prompt Injection
↓
LLM 產生惡意 HTML
↓
Frontend 直接 Render
↓
XSS
這裡:
Prompt Injection
→ 前面的攻擊入口
而:
Improper Output Handling
→ 後面沒有安全處理 LLM Output
兩條可以一起發生。
如果前面 Prompt Injection 成功,
但後面的 Backend 有做好:
Validation
Sanitization
Authorization
攻擊可能還是會被擋下來。
所以這也是為什麼不能只想:
我要做出一個永遠不會被騙的 LLM。
更實際的想法應該是:
就算 LLM 被騙了,後面的系統也不要直接跟著做。
我自己會整理成幾個比較直覺的方向。
這是最重要的一件事。
不要:
LLM Output
↓
相信
↓
執行
而是:
LLM Output
↓
驗證
↓
清理
↓
檢查權限
↓
才交給下一個系統
簡單來說:
AI 產生的內容,也要過跟 User Input 類似的安全檢查。
LLM Output 要去哪裡,
處理方式就不一樣。
例如:
要放進 HTML
→ HTML Encoding / Sanitization
要進 Database
→ Parameterized Query
要組 File Path
→ Path Validation
要呼叫 API
→ Schema Validation
要執行 Tool
→ Authorization
不能只有一個:
sanitizeOutput()
然後幻想什麼地方都能通用🤣
真正重要的是:
下一個系統會怎麼解讀這段內容?
如果可以,
盡量不要讓:
LLM
↓
自由產生 SQL
↓
Database Execute
比較安全的方式可能是:
LLM
↓
產生結構化條件
↓
Backend 自己組 Query
↓
Parameterized Query
例如讓 AI 回:
{
"status": "active",
"createdAfter": "2026-01-01"
}
再由 Backend 決定:
這些欄位最後要怎麼安全地轉成 SQL。
這會比:
AI,請直接幫我寫完整 SQL。
再無條件 Execute,
安全很多。
假設 LLM 說:
我要呼叫 refundOrder
orderId = 123
Backend 不應該只是:
AI 說要退款,好喔。
🤣
還是需要檢查:
這個 User 有退款權限嗎?
Order 123 是他的嗎?
訂單真的符合退款條件嗎?
目前有沒有已經退款?
也就是:
LLM 負責提出要做什麼,Backend 負責決定到底能不能做。
不要因為 Code 是 AI 產生的,
就跳過:
Code Review
Static Analysis
Security Scan
Test
CI/CD Check
反而應該把它當成:
一個你還不確定品質的 Contributor 寫的 Code。
🤣
AI 可以幫忙加速。
但它產生的 Code 還是 Code。
一樣可能有:
Bug
Security Vulnerability
錯誤邏輯
危險 Dependency
假設某個 AI 功能真的被 Prompt Injection 影響,
如果它後面的 Service Account 只有:
Read Only
攻擊影響通常就比較有限。
但如果它是:
Admin
那同一段惡意 Output,
造成的結果可能完全不同。
所以 Improper Output Handling 跟前面 Excessive Agency 又會連在一起。
簡單來說:
就算 Output Handling 哪天漏了一層,最小權限還是可以再幫你擋一層。
做到這裡,
其實會發現今天這條非常像傳統 Application Security。
以前我們一直在講:
Never trust user input.
到了 AI Application,
只是多了一個新的輸入來源:
LLM Output。
因為整個流程其實變成:
User
↓
LLM
↓
Application
↓
Database / Browser / Shell / API
對後面的:
Database
Browser
Shell
API
來說,
LLM Output 就是它們收到的 Input。
所以今天我會記:
不要因為內容是 AI 產生的,就把它當成可信資料。
LLM 可以產生:
SQL
HTML
JavaScript
Command
File Path
Code
Tool Parameter
但:
產生 ≠ 可以直接執行。
真正安全的流程應該是:
LLM Output
↓
Validate
↓
Sanitize / Encode
↓
Authorization
↓
限制權限
↓
才交給下一個系統
而且我覺得這一條也很適合拿來幫整個 OWASP LLM Top 10 2026 收尾。
從 Day 05 開始,
我們一路看了:
Prompt 怎麼進來
↓
資料會不會洩漏
↓
AI 能做多少事情
↓
Model 從哪裡來
↓
資料有沒有被污染
↓
資源有沒有邊界
↓
AI 講的資訊能不能信
↓
Hidden Context 會不會暴露
↓
RAG 找到的資料對不對
↓
最後 AI 產生的東西怎麼被使用
最後其實又回到一個非常熟悉的資安觀念:
不要相信任何跨越安全邊界進來的資料。
以前是 User Input。
現在多了一個:
Model Output。
AI 可以幫你決定:
「我覺得下一步應該做這個。」
但真正的 Application 還是要再問一次:
「好,但這件事真的可以做嗎?」
這一層不能省🤣