CodeVetter · Repo Unpack · Risk map
harry0703/MoneyPrinterTurbo
The largest risk is the default-open posture: empty api_key means no authentication while listen_host defaults to 0.0.0.0, exposing task creation, file uploads, and artifact downloads to the LAN. Redis state uses ast.literal_eval on stored values inside a documented trust boundary. Several code paths shell out (ffmpeg probing of uploaded media, the claude_code provider spawning the local claude CLI). Paid text-to-video providers create billable remote tasks — guarded by CLI confirm flags but only a config/api-key check on the API path. The 8k-line webui/Main.py and duplicated requirements.txt are maintainability hotspots.
- Authentication is opt-in: when app.api_key is empty verify_token returns immediately and every /api/v1 route plus /tasks downloads are open; combined with listen_host='0.0.0.0' default, an unconfigured instance is LAN-exposed (the code only logs a warning at startup).
- RedisState._convert_to_original_type applies ast.literal_eval to values read from Redis; the class docstring explicitly documents Redis as a trust boundary — a Redis DB writable by other tenants could inject crafted task records.
- Uploaded media is probed by FFmpeg/ffprobe subprocesses (MATERIAL_VALIDATION_TIMEOUT_SECONDS=120) and PIL for images — attacker-controlled files reach the media toolchain; mitigations are extension whitelist, size caps (200MB video/20MB image), UUID storage names, and filename character sanitization.
- The claude_code LLM provider shells out to the locally installed `claude` CLI; build_claude_code_env scrubs conflicting ANTHROPIC_*/CLAUDE_CODE_USE_* env vars and Docker deployment requires injecting CLAUDE_CODE_OAUTH_TOKEN — a subscription credential — into the container environment.
- Paid material sources (wavespeed, volcengine_seedance, ofox, muapi, metaso_minimax, loomloom) create billable remote tasks; the CLI requires --confirm-*-charge flags and WebUI requires confirmation, but the HTTP API path only checks is_enabled() — an unauthenticated caller could spend money if api_key is unset.
- config.toml persists all provider API keys in plaintext at repo root and is rewritten atomically by save_config on WebUI interactions; config.example.toml warns not to commit it, and logs deliberately avoid printing keys (material._redact_secret, llm._sanitize_error_message).
- webui/Main.py is a single 8,262-line module mixing i18n, settings persistence, task history, upload handling, and generation orchestration — a high blast-radius file where any edit risks regressions across many features.
- Duplicate dependency manifests: requirements.txt mirrors pyproject.toml 'for legacy pip' while Docker builds use requirements.txt and CI uses uv.lock — version drift between the two lists would produce different runtime vs tested environments.
- Dockerfile runs `chmod 777 /MoneyPrinterTurbo` and mounts the whole repo into containers; combined with Streamlit's --server.enableCORS=True in the launch command, container posture is more permissive than the API's own Origin checks.
- VideoParams field defaults (subtitle_position, custom_position, subtitle display/animation) read config.ui at class-definition/import time — a stale or invalid config.toml value is frozen into the pydantic model before validation can run; cli.py documents this and keeps its own fallback constants.
- Cross-post process-liveness detection uses os.kill(pid, 0) on POSIX and a Win32 OpenProcess/GetExitCodeProcess path — best-effort heuristics where a PID reuse could keep a dead task marked busy; foreign-host owners are conservatively treated as alive.
- save_config has an EBUSY fallback that writes config.toml in place when atomic replace fails (Docker bind-mounted single file) — a crash mid-write there could leave a truncated config.