Skip to content

fix: prevent admin privilege escalation via signup#22

Closed
study8677 wants to merge 1 commit into
mainfrom
codex/propose-fix-for-public-signup-vulnerability
Closed

fix: prevent admin privilege escalation via signup#22
study8677 wants to merge 1 commit into
mainfrom
codex/propose-fix-for-public-signup-vulnerability

Conversation

@study8677
Copy link
Copy Markdown
Owner

Motivation

  • The public signup flow could claim a bootstrap admin row (created with password_hash == "!unusable") or implicitly create the configured admin email as an admin, allowing unauthenticated privilege escalation on fresh/unclaimed deployments.

Description

  • In create_user_with_account added a guard that treats an existing !unusable admin row as taken and raises ValueError("email_exists") for signups that try to claim OPENCMO_ADMIN_EMAIL by matching the normalized email.
  • Removed the implicit admin role assignment for self-service signups so inserted users always get role "user" rather than being promoted to "admin" when they match OPENCMO_ADMIN_EMAIL.
  • The change is contained to src/opencmo/storage/accounts.py and preserves normal signup/account creation and the explicit bootstrap logic that runs at DB init.

Testing

  • Attempted to run focused tests with pytest tests/test_trial_platform.py::test_signup_login_me_and_logout and pytest tests/test_trial_platform.py::test_admin_summary_requires_admin tests/test_trial_platform.py::test_admin_account_actions_update_and_disable_access, but the test runs failed to collect/execute because the environment in this container is missing runtime dependencies (aiosqlite) and the test runner could not import the opencmo package.
  • No automated test failures were observed in-repo as a result of the code edits because the test environment could not run; the change was verified by local code inspection and by confirming the updated lines in src/opencmo/storage/accounts.py.

Codex Task

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ef89774051

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +193 to +194
if row and row[1] == "!unusable" and normalized == admin_email:
raise ValueError("email_exists")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve bootstrap path for configured admin account

This guard locks out admin bootstrap on fresh deployments: _ensure_admin_account seeds OPENCMO_ADMIN_EMAIL with password_hash='!unusable', and authenticate_user rejects unusable hashes, so the only in-app way to claim that row was signup updating the password. After this change, signup for that email always returns email_exists, leaving no API path to ever set an admin password and making /api/v1/admin/* inaccessible unless operators manually edit the DB.

Useful? React with 👍 / 👎.

study8677 added a commit that referenced this pull request May 21, 2026
* fix: validate and dedupe geo ask platforms

* fix: bind docker compose port to localhost by default

* fix: prevent verify-email auth bypass for verified users

* fix: fail closed for account-scoped publish credentials

* fix: prevent admin privilege escalation via signup

* test: update admin/publisher tests for security fixes

- test_publishers.py: replace env vars with llm.set_request_keys() since
  publish credentials no longer fall back to os.environ (account-scoped).
- test_trial_platform.py: add _seed_admin() helper that activates the
  bootstrapped !unusable admin row directly, since signup can no longer
  claim that row to prevent admin privilege escalation.

* test: fix ruff I001 import order
@study8677
Copy link
Copy Markdown
Owner Author

Incorporated via #27 → main.

@study8677 study8677 closed this May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant