掃描日期:2026-09-05 掃描版本:jedi-python-package
main@67cb075工具:Claude Codeclaude-securityplugin v0.10.2.3 狀態:⚠️ 未經工具的驗證面板審查(掃描在研究階段中止,見文末「這份清單的可信度」) 裁決狀態:⬜ 全部待裁決
19 條獨立問題。7 條 HIGH(其中 5 條是可直接繞過登入的認證缺陷)、9 條 MEDIUM、3 條 LOW。
問題高度集中在 LDAP/AD 登入路徑(單一檔案 ldap_adapter.py 佔 7 條), 以及 RLS 租戶隔離的 fail-open 預設(jedi_common/session/database/db.py)。
我已對全部 7 條 HIGH 與部分 MEDIUM 開檔核對過原始碼,核對結果記在每條的「實查」欄。
jedi-iam/jedi_iam/infra/adapter/authenticate_adapter/ldap/ldap_adapter.py:67 connect()Connection() 的 user 與 password 都傳 None(那兩個參數有 if self.is_ad 條件), 所以走的是匿名 bind。之後只用 search 找到條目就當作登入成功,使用者輸入的密碼從頭到尾沒有跟目錄驗證過。connect() 第 64-68 行 user=username if self.is_ad and username else None, 非 AD 分支確實不帶憑證;verify_user() 拿到 conn 後直接查使用者資訊就回傳。user_auth_providers 綁定紀錄。:144 get_open_ldap_user_info()、:185 get_ad_user_info()search_filter = f'(cn={username})',username 未做任何 escape。username=* 就讓 filter 變成 (cn=*) 匹配全目錄,取第一筆的 entryUUID 去對綁定表,等於任意帳號登入。ldap3.utils.conv.escape_filter_chars 處理,並在序列化層限制帳號字元集。:49 _get_ldap_server()Server(...) 沒有傳 Tls 物件,ldap3 的預設是 validate=CERT_NONE, 等於設了 SSL/STARTTLS 卻不驗伺服器憑證與 hostname。Server(server, port, use_ssl=..., get_info='ALL', connect_timeout=20),無 tls= 參數。Tls(validate=ssl.CERT_REQUIRED, ca_certs_file=...) 並開啟 hostname 檢查,無法驗證時 fail closed。jedi-iam/jedi_iam/infra/adapter/authenticate_adapter/google_auth/google_auth_adapter.py:52authenticate() 只拿 username 去查 user_auth_providers 有沒有對應綁定,查到就回 UserDTO,密碼參數完全沒用到。login_service.py:51 依 provider 派送 adapter, auth_factory.py:14 有 AuthenticateType.GOOGLE: GoogleAuthAdapter 註冊,所以這條路徑是活的。jedi-iam/jedi_iam/app/service/user_auth_provider_service.py:99 register_ad_user()user_uid 參數後直接 verify_user_exist(user_uid) 就建立綁定, 沒有檢查 caller 是不是本人、也沒有檢查 caller 有沒有管理他人身分的權限。register_ldap_user(:108)、register_google_user(:141)同樣沒有。user_uid == 從 JWT 解出的 caller,或要求 caller 具備管理他人身分的 capability。jedi-iam/jedi_iam/api/routes/otp_route.py:102 MfaVerifyRoute.post@auth_required(註解說明是登入第二關),但只要 uid + 六位數 code 正確就發 access/refresh token。 沒有任何嘗試次數限制。generate_jwt_token(user.uid)。/otp-resend 維持一個有效碼,然後無限次暴力猜。/otp-verify 綁定一個「密碼驗證通過後才發出的短期挑戰 token」。jedi-common/jedi_common/session/database/db.py:117session_scope() 的 elif is_pg: 分支在沒有 user context 時直接設 app.is_super_admin = 't',等於關閉 RLS。@transaction 都以 super admin 執行。 主專案在 before_request 會把 context 重設為 None,所以任何漏掛 JWT 檢查的路由、公開端點、 或沒還原 context 的背景執行緒,都會踩到。:102is_super = (not user_ctx.tenant_id) or ...——tenant_id 是 None 或 0 都算 super admin。X-Tenant-ID: 0 就看到整張 roles 表。is_platform 布林值。jedi-iam/jedi_iam/authz/signed_token.py:89tenant_id 設為 None,於是踩到 M-2 變成 super admin。jedi-iam/jedi_iam/turnstile/verifier.py:38 _resolve_secret_key()if not raw: return _ALWAYS_PASS_TEST_KEY——secret 沒設就用 Cloudflare 的公開測試金鑰, 該金鑰的行為是「永遠驗證通過」。ldap_adapter.py:87 test_connect()LDAP_USER / LDAP_SECRET 去 bind 呼叫端指定的伺服器。test_connect() 就是 self.connect(self.config.LDAP_USER, self.config.LDAP_SECRET)。ldap_adapter.py:73jedi-iam/jedi_iam/common/utils/redis_client_util.py:39redis.Redis(..., ssl=self.__REDIS_SSL, ssl_cert_reqs=False, ...)—— 即使開了 SSL 也不驗憑證。ssl_cert_reqs=False 是寫死的。ssl=True 時傳 ssl_cert_reqs="required" 與 ssl_check_hostname=True。jedi-common/jedi_common/utils/audit_log.py:34system_logs 的訊息字串。jedi-remote-agent 的 agent 註冊流程會把 hardware_info.hostname 一路帶進 holder_name。此條我尚未開檔核對 jedi-remote-agent 側,待驗。[AUDIT:...] 事件行、汙染下游 SIEM 解析。無程式碼執行風險。jedi-iam/jedi_iam/infra/adapter/authenticate_adapter/password/password_adapter.py:27jedi-iam/jedi_iam/app/service/import_user_service.py:79upload_dir = os.path.join(uploads_dir, username),username 取自 login_name, 未經 secure_filename 或 basename 處理。.. 的帳號存在(帳號建立端目前無格式驗證), 且該帳號具備 user.create 權限。前提偏窄。os.path.basename。random.randint 而非密碼學安全亂數jedi-iam/jedi_iam/mfa/app/service/email_service.py:63code = str(randint(100000, 999999))。secrets.randbelow(900000) + 100000,驗證時用 hmac.compare_digest 比對。jedi-common/jedi_common/interfaces/entities/page_meta_entity.py:19PagerSchema.page_size 的上限驗證被刻意移除,page_size=0 會讓 (total + page_size - 1) // page_size 除以零。validate.Range(min=1, max=<合理上限>),並在 __post_init__ 獨立防呆。jedi-iam/jedi_iam/plugin.py:191core/iam_wiring.py 已明確設為 True,Guidant AI 目前不受影響。 問題在共用元件的預設值不安全,其他 consumer 忘了接線就會裸奔。這是我的建議,實際優先序由決策者裁決。
第一批(登入可被繞過,建議優先):H-1、H-2/H-7、H-4、H-5、H-6 第一批的共同性質是「不需要有效憑證就能取得他人身分」,其中 H-1 與 H-2 疊加後是完整的無密碼登入。
第二批(租戶隔離 fail-open):M-1、M-2、M-3 三條同根因,建議一起改 session_scope() 的 super admin 判定,並補守衛測試。 M-2 的註解顯示曾實際發生,改動前要先盤點有多少呼叫端依賴目前的 fail-open 行為。
第三批(傳輸與設定安全):H-3、M-4、M-5、M-7 第四批(其餘):M-6、M-8、M-9、M-10、L-1、L-2、L-3
必讀:這些是研究員 agent 的原始宣稱,沒有經過工具內建的三人驗證面板。 掃描在研究階段就因 session 額度用盡而中止,面板從未執行。
我已補做的核對:
尚未核對的:
原始掃描資料(32 筆去重前的完整 JSON,含 evidence 與 snippet)在 ~/.claude/projects/.../subagents/workflows/wf_442f835c-ddf/journal.jsonl。