Gitea 官方 Docker 映像檔在 2026 年 7 月被指出存在一個 CVSS 9.8 的高風險漏洞:CVE-2026-20896。問題不在程式碼、不在 Golang 相依套件,也不在容器 runtime,而在映像檔內建的 app.ini 範本裡有一行 REVERSE_PROXY_TRUSTED_PROXIES = *。任何用官方映像檔搭起 Gitea、又順手把 ENABLE_REVERSE_PROXY_AUTHENTICATION 開起來的站點,等於在對外的 HTTP 埠上掛了「送個 header 就能變成任何人」的開關,包含管理員帳號。Sysdig 統計約有 6,200 台可從網際網路直連的 Gitea 實例,而外部利用嘗試在公告後 13 天就被觀察到。
一行預設值決定的信任邊界
Gitea 支援讓外部的 authenticating reverse proxy(例如 Authelia、Authentik 或 nginx auth request)先驗證使用者身份,再把使用者名寫進 HTTP 標頭傳給 Gitea。這是常見的 SSO 整合作法:應用不必自己實作 OIDC/SAML,只要信任前端代理夾帶的 X-WEBAUTH-USER、X-WEBAUTH-EMAIL 等自訂欄位。
這個模式的安全前提有兩個。第一,ENABLE_REVERSE_PROXY_AUTHENTICATION 必須被明確打開;第二,REVERSE_PROXY_TRUSTED_PROXIES 必須限縮到真正的代理伺服器 IP 範圍。Gitea 原始碼裡的 app.ini 範本原本把後者預設成 127.0.0.0/8,::1/128,也就是只信任本機來源。
Docker 映像檔另外維護的 app.ini 範本,卻在某個時間點被改成 REVERSE_PROXY_TRUSTED_PROXIES = *。這個萬用字元代表「任何 IP 都可以是代理」。單獨看這行不會造成問題,因為 ENABLE_REVERSE_PROXY_AUTHENTICATION 預設仍為 false。可是自架社群裡想要把 Gitea 整合進 SSO 的人非常多,官方文件甚至以此為主要用例;只要有人跟著教學把認證開關切到 true,信任邊界就在毫無警訊下瓦解。
Docker 映像檔為什麼跟原始碼版本行為不同
Docker 映像檔多半會為容器化情境提供不一樣的預設值,原意是替使用者省掉調校。像資料庫連線字串預設指向 /data、SSH port 綁到 2222,都是常見的例子。REVERSE_PROXY_TRUSTED_PROXIES 被改成 * 是這套思路的延伸:在 Docker 網路裡,反向代理不會固定 IP,反正只信任本機的話,無論 Traefik、Caddy 或另一個容器裡的 nginx 都得額外開 host mode 才能連通,不如乾脆放寬。
問題是這個決定沒有把「認證開關預設為關」跟「信任範圍預設為全開」這兩個獨立變數視為互相依賴。從資訊安全角度,任何一個信任 header 的功能,只要曾經被打開過,就必須確保觸發它的 header 只可能來自受信任的來源。「使用者不會打開這個功能」不是一個能建立信任邊界的假設,尤其當上游把這個功能寫在教學裡、把 SSO 當賣點來推。
原始碼安裝版本沒有這個問題,因為 upstream 的 app.ini.sample 保留了較嚴格的預設。這也解釋了為什麼漏洞公告特別把「Docker 映像檔」寫進標題:編譯自 source 或用 apt 套件安裝的 Gitea,即使打開 reverse proxy 認證,依然只信任 loopback,除非管理員主動把設定放寬。
攻擊怎麼發生:一個 curl 就夠
利用手法簡單到不需要 exploit framework。攻擊者只要能在 TCP 層碰到 Gitea 的 HTTP 埠(預設 3000,對外通常是 80/443),丟出一個包含 X-WEBAUTH-USER 標頭的請求就結束了:
1 | GET / HTTP/1.1 |
Gitea 看到 REVERSE_PROXY_TRUSTED_PROXIES = *,認定請求端可以扮演代理角色;再看到 X-WEBAUTH-USER: admin,就把這個連線當作 admin 帳號的合法工作階段。攻擊者接下來可以呼叫任何 API、建立個人存取權杖、增加 SSH 金鑰、修改倉庫、竊取 CI/CD 密鑰,一路做到 supply chain 汙染。
PoC 檢查工具的邏輯只有三步:抓首頁的 footer 判斷版本、對已知或推測的使用者名稱送 X-WEBAUTH-USER、看回應頁面標題是否出現登入後的儀表板。整套流程可以掃描網際網路上的 Gitea 實例,但真正的高價值目標其實是內網 CI 或私有雲平台裡跑的 Gitea,很多團隊把它當作 GitHub 的替代品,信任邊界依賴的是「反正只有內部同事會用」。這個假設在漏洞公告之後不再成立。
立刻該做的處置與版本升級
Gitea 官方在 2026 年 6 月底釋出 1.26.3,把 Docker 映像檔內的 REVERSE_PROXY_TRUSTED_PROXIES 從 * 改回文件建議的 loopback 預設,並且把 reverse proxy 認證改為明確 opt-in。7 月初的 1.26.4 又補強了幾個相關檢查。使用官方映像檔的站點應該直接升級到 1.26.4 或更新版本,不要停在 1.26.3。
升級之後,還必須驗證三件事。第一,實際檢查現在容器內的 app.ini。有些自架站點把整個 custom/conf/app.ini 掛載進容器,升級映像檔並不會覆蓋自訂設定,原本被寫死的 * 依然留著。第二,在反向代理層明確剝除來自使用者的身分標頭。Caddy 可以用 header_up -X-WEBAUTH-USER;nginx 用 proxy_set_header X-WEBAUTH-USER "" 直接清空。任何位在信任層外的請求都不應該被允許夾帶身分欄位進來。
第三,把 Gitea 容器的 HTTP 埠從主機介面上拿掉,只讓反向代理連得到。這件事在 Docker Compose 裡的差別只有 ports: ["3000:3000"] 跟 expose: [3000] 一字之隔,但語意上是把埠對外開放、跟只允許同一個 Docker network 內部連線的分野。以 CVE-2026-20896 為例,只要主機的 3000/tcp 沒有暴露到公開網際網路,即便設定檔仍舊寫著 *,外部利用也需要先繞過主機防火牆。
已經上線一段時間的站點需要進一步做鑑識:翻遍存取記錄,找出任何來自非預期 IP 的 X-WEBAUTH-USER 標頭出現;比對管理員帳號的登入時區與 IP 分布;檢視 SSH 金鑰、個人存取權杖、Webhook 是否有沒印象添加的項目;假如有 CI/CD 整合,要把所有部署金鑰跟 API 憑證輪替一次。憑證失竊是這類漏洞真正昂貴的部分,補完程式碼還要清理外洩秘密。
Header-based 認證的信任模式該重寫
CVE-2026-20896 的深層問題不是 Gitea 一家的事。凡是接受「上游代理告訴我使用者是誰」的服務,包括早期版本的 Grafana、部分 Kubernetes dashboard、內部 wiki 系統,設計上都存在同樣的陷阱:應用相信自己收到的請求已經穿過認證代理,但這件事在 TCP 層沒有辦法真正驗證,只能靠部署者確保不受信任的網路碰不到後端。
實務上比較穩健的處理方式,是把 header-based auth 當作額外密封層,而不是唯一防線。做法有幾種可以考慮:在應用層繼續啟用一個內部密鑰或 mTLS,讓即便標頭被偽造,沒有對應的憑證還是無法建立工作階段;或者選擇 protocol-level 的 SSO 方案,例如直接讓 Gitea 走 OIDC,把身分驗證交給 IdP 完成,而不是相信一段可被偽造的 HTTP 欄位。對於大部分自架團隊,後者更值得推行,OIDC 的信任模型建立在簽章與 token 上,不會因為代理設定失手而崩潰。
一味相信「反向代理會擋掉直連」也是一個危險假設。容器編排網路、host networking mode、反向代理的 backend 節點如果直接暴露、或者 Docker port publish 走 IPv6 卻沒對 IPv6 加防火牆規則,都可能讓看似不對外的埠意外可達。安全預設(secure-by-default)的概念在容器映像檔尤其重要,因為映像檔幾乎沒有機會像作業系統套件那樣,在初次安裝時跳出提示要求使用者確認設定。
自架 Git 服務的下一步
Gitea 這次的教訓對正在或準備自架 Git、CI/CD、內部工具平台的團隊有幾個提醒。設定檔差異必須寫進 runbook,不能只信任「跟著官方 Docker 教學做」;反向代理的信任邊界要靠網路隔離跟明確 IP 限制建立,不是靠萬用字元;而 SSO 的整合方式,能走 OIDC/SAML 這類密碼學驗證就別走 header injection。
自架的核心成本從來不是購買硬體,而是持續維運。CVE-2026-20896 這樣的漏洞從公告到大規模掃描不到兩週,如果自架的機器沒有可靠的網路隔離、沒有觀測資料能查詢異常請求、沒有升級流程能在 24 小時內把版本推上去,自架帶來的自由度會很快變成負債。
NCSE Network 提供的臺灣是方電訊機房 VPS 搭配 Intel Gold CPU 與 NVMe SSD,適合作為自架 Gitea、Forgejo 或其他內部 Git 平台的基礎;獨立的防火牆規則、完整的 IPv6 支援,可以協助團隊把「應用只允許反向代理連線」這件事落實在網路層,而不是留給應用設定檔的預設值決定。想了解更完整的自架環境規劃或 IP Transit 選項,可以到 https://ncse.tw 進一步查看方案。