제출 #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. PM 04:06 (1 월 ago)
모더레이션2026. 07. 18. PM 02:25 (1 month later)
상태수락
VulDB 항목380046 [jxxghp MoviePilot 까지 2.13.5 Application API /jxxghp/MoviePilot 권한 상승]
포인트들20

Interested in the pricing of exploits?

See the underground prices here!