提出 #858227: jxxghp MoviePilot v2.13.5 Missing Authorization情報

タイトルjxxghp MoviePilot v2.13.5 Missing Authorization
説明https://github.com/jxxghp/MoviePilot Title: Any authenticated (non-admin) user can read all system settings and secrets via /api/v1/system/env and /api/v1/system/setting/{key} ### Summary The `GET /api/v1/system/env` and `GET /api/v1/system/setting/{key}` endpoints are documented as admin-only but are guarded by `get_current_active_user_async`, which only checks that the account is active, not that it is a superuser. Any authenticated non-admin user can therefore read the full settings object, which includes secrets such as the database password, the application API token, the GitHub token, and configured third-party API keys. ### Details `app/api/endpoints/system.py`: ```python @router.get("/env", summary="查询系统配置", ...) async def get_env_setting(_: User = Depends(get_current_active_user_async)): """查询系统环境变量,包括当前版本号(仅管理员)""" # docstring says admin-only info = settings.model_dump(exclude={"SECRET_KEY", "RESOURCE_SECRET_KEY"}) # only 2 fields hidden ... return schemas.Response(success=True, data=info) @router.get("/setting/{key}", ...) async def get_setting(key: str, _: User = Depends(get_current_active_user_async)): """查询系统设置(仅管理员)""" if hasattr(settings, key): value = getattr(settings, key) ... ``` The dependency only enforces "active", not "superuser" (`app/db/user_oper.py`): ```python async def get_current_active_user_async(current_user: User = Depends(get_current_user_async)) -> User: if not current_user.is_active: raise HTTPException(status_code=403, detail="用户未激活") return current_user # no is_superuser check async def get_current_active_superuser_async(current_user: User = Depends(get_current_user_async)) -> User: if not current_user.is_superuser: raise HTTPException(status_code=400, detail="用户权限不足") # the correct gate return current_user ``` `settings.model_dump(exclude={"SECRET_KEY", "RESOURCE_SECRET_KEY"})` hides only those two fields. Everything else defined in `app/core/config.py` is returned, including `DB_POSTGRESQL_PASSWORD`, `API_TOKEN` (the app's own API token used to authenticate webhook and automation calls), `GITHUB_TOKEN`, `TMDB_API_KEY`, `COOKIECLOUD_PASSWORD`, `FEISHU_APP_SECRET`, and any configured downloader/LLM credentials. `/setting/{key}` returns any single named setting (for example `API_TOKEN`) directly. Exposure of `API_TOKEN` lets a low-privileged user authenticate to token-protected endpoints, so the impact extends beyond disclosure to privilege escalation. ### PoC Validated with the dependency functions (`app/db/user_oper.py:50` and `:74`), the exclusion set (`system.py:507`), and config field names. A non-admin (active, non-superuser) account is accepted by the `/env` gate but rejected by the correct superuser gate: ``` Non-admin -> GET /api/v1/system/env : 200 {"DB_POSTGRESQL_PASSWORD":"prod-db-pass", "GITHUB_TOKEN":"ghp_realtoken","TMDB_API_KEY":"tmdb-key","API_TOKEN":"app-api-token","SUPERUSER":"admin"} Non-admin -> GET /admin-only (superuser gate): 400 {"detail":"用户权限不足"} ``` Against a live instance, as any non-admin user: ``` curl -s -H "Authorization: Bearer <non-admin-jwt>" "$TARGET/api/v1/system/env" curl -s -H "Authorization: Bearer <non-admin-jwt>" "$TARGET/api/v1/system/setting/API_TOKEN" ``` ### Impact In any multi-user MoviePilot deployment, a regular (non-admin) user can read all system secrets: database credentials, the application API token, the GitHub token, and configured third-party API keys. With the leaked `API_TOKEN` the user can reach token-authenticated endpoints, escalating beyond read-only disclosure. Secondary (same root cause, missing/incorrect authorization, found but not the focus of this report): `GET /api/v1/plugin/file/{plugin_id}/{filepath}` (`app/api/endpoints/plugin.py`) has no authentication dependency (path traversal itself is blocked, but plugin files are served to unauthenticated callers); `POST /api/v1/user/avatar/{user_id}` (`app/api/endpoints/user.py`) updates the avatar of an arbitrary `user_id` without checking it matches the caller. Suggested remediation: change `/env` and `/setting/{key}` to `Depends(get_current_active_superuser_async)`, and additionally redact secret-bearing fields from the settings dump rather than excluding only two keys.
ソース⚠️ https://github.com/jxxghp/MoviePilot/issues/5916
ユーザー
 geochen (UID 78995)
送信2026年06月14日 16:06 (1 月 ago)
モデレーション2026年07月18日 14:25 (1 month later)
ステータス承諾済み
VulDBエントリ380046 [jxxghp MoviePilot 迄 2.13.5 Application API /jxxghp/MoviePilot 特権昇格]
ポイント20

Might our Artificial Intelligence support you?

Check our Alexa App!