Skip to content

fix: require admin auth for glitch controls#4884

Open
saim256 wants to merge 3 commits into
Scottcjn:mainfrom
saim256:fix-glitch-admin-auth
Open

fix: require admin auth for glitch controls#4884
saim256 wants to merge 3 commits into
Scottcjn:mainfrom
saim256:fix-glitch-admin-auth

Conversation

@saim256
Copy link
Copy Markdown

@saim256 saim256 commented May 12, 2026

Summary

  • add default-deny admin authentication for Glitch API destructive/configuration routes
  • require matching GLITCH_ADMIN_KEY via X-Admin-Key or X-API-Key
  • protect history clear, config update/reset, enable, disable, and manual trigger endpoints
  • add Flask route tests for wrong-key, unconfigured-key, and valid-key behavior

Fixes #4874

/claim #4874

Wallet: RTC253255d034065a839cd421811ec589ae5b694ffc

Validation

  • python -m pytest issue2288\glitch_system\tests\test_glitch_system.py -q -> 43 passed
  • python -m py_compile issue2288\glitch_system\src\api.py issue2288\glitch_system\tests\test_glitch_system.py -> passed
  • git diff --check -> passed
  • python tools\bcos_spdx_check.py --base-ref origin/main -> OK

@github-actions github-actions Bot added BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) api API endpoint related labels May 12, 2026
@github-actions github-actions Bot added the size/M PR: 51-200 lines label May 12, 2026
@saim256
Copy link
Copy Markdown
Author

saim256 commented May 12, 2026

Pushed follow-up commit \�09a88c\ to preserve the existing malformed-JSON validation behavior on the two JSON mutating routes before the admin gate.\n\nLocal verification after the follow-up:\n- \python -m pytest issue2288\glitch_system\tests\test_glitch_system.py tests\test_glitch_api_input_validation.py -q\ -> 52 passed\n- \python -m py_compile issue2288\glitch_system\src\api.py issue2288\glitch_system\tests\test_glitch_system.py tests\test_glitch_api_input_validation.py\ -> passed\n- \git diff --check\ -> passed\n- \python tools\bcos_spdx_check.py --base-ref origin/main\ -> OK\n\nThe main CI test job is green after this update; only the BCOS engine scan was still running at last check.

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great contribution! LGTM.

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great contribution! LGTM.

Copy link
Copy Markdown

@idontwantagoldfish83 idontwantagoldfish83 left a comment

Choose a reason for hiding this comment

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

I found one blocking auth edge case in the new guard.

require_admin() calls hmac.compare_digest(provided_key, expected_key) on user-controlled header strings. For str inputs, Python raises TypeError when either value contains non-ASCII characters, so a malformed admin header returns a 500 instead of the same 401 used for missing or wrong keys.

I reproduced this on the PR branch with GLITCH_ADMIN_KEY=test-admin:

resp = client.post("/api/glitch/disable", headers={"X-Admin-Key": "é"})

Actual result: Flask logs TypeError: comparing strings with non-ASCII characters is not supported and returns 500 Internal Server Error. This affects every route protected by require_admin(), since they all pass through the same comparison.

Expected result: malformed/non-matching credentials should be treated as unauthorized and return the normal 401 response without surfacing an unhandled exception.

A durable fix would be to normalize both values to bytes before the constant-time comparison, for example:

provided_key_bytes = provided_key.encode("utf-8")
expected_key_bytes = expected_key.encode("utf-8")
if not hmac.compare_digest(provided_key_bytes, expected_key_bytes):
    ...

Alternatively, catch TypeError around the comparison and return the same unauthorized response, but byte normalization keeps the path simple and preserves constant-time comparison semantics for Unicode-capable secrets too. Please add a regression test that sends a non-ASCII X-Admin-Key and asserts a 401.

Validation I ran:

  • .venv/bin/python -m pytest issue2288/glitch_system/tests/test_glitch_system.py::TestGlitchAPIAdminAuth tests/test_glitch_api_input_validation.py -q -> 12 passed
  • .venv/bin/python -m pytest issue2288/glitch_system/tests/test_glitch_system.py tests/test_glitch_api_input_validation.py -q -> 51 passed, 1 existing stochastic failure in TestGlitchEngineIntegration.test_conversation_flow

Copy link
Copy Markdown

@loganoe loganoe left a comment

Choose a reason for hiding this comment

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

Approved. This secures the correct issue2288/glitch_system/src/api.py mutating routes with a default-deny admin key while preserving the existing JSON validation behavior for the routes that parse request bodies.

Validation performed:

  • git diff --check origin/main...HEAD
  • python3 -m py_compile issue2288/glitch_system/src/api.py issue2288/glitch_system/tests/test_glitch_system.py
  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 /tmp/rustchain-flask-venv/bin/python -m pytest -q issue2288/glitch_system/tests/test_glitch_system.py -> 43 passed, 6 subtests passed

@galpetame
Copy link
Copy Markdown

galpetame commented May 12, 2026

Review for #4884

The patch is focused and the existing test suite passes locally (43 passed, 6 subtests). I found one auth-boundary issue worth tightening before merge.

Two admin-only routes still parse and validate JSON before the admin check:

  • PUT /api/glitch/config: get_json_object() runs before require_admin().
  • POST /api/glitch/trigger: get_json_object() runs before require_admin().

Local probe against the current PR head:

  • PUT /api/glitch/config with string JSON + wrong admin key -> 400
  • POST /api/glitch/trigger with string JSON + wrong admin key -> 400
  • POST /api/glitch/disable with valid X-API-Key alias -> 200

This does not allow mutation without the admin key, but it means wrong-key/unauthenticated callers can still reach request-body validation on two routes and get 400 JSON object required before the admin gate. For a default-deny admin boundary, I would expect those requests to fail with 401 before any body validation.

Suggested fix:

  1. Move require_admin() before get_json_object() in update_config() and trigger_glitch().
  2. Add a regression where wrong/missing admin key plus non-object JSON returns 401.
  3. If X-API-Key remains supported as an alias, add one positive alias test so that behavior is intentional and covered.

Validation I ran:

  • git diff --stat origin/main HEAD -> 2 files changed, 109 insertions(+), 4 deletions(-)
  • git diff --check origin/main HEAD -- issue2288/glitch_system/src/api.py issue2288/glitch_system/tests/test_glitch_system.py -> passed
  • python -m py_compile issue2288/glitch_system/src/api.py issue2288/glitch_system/tests/test_glitch_system.py -> passed
  • python -m pytest issue2288/glitch_system/tests/test_glitch_system.py -q -> 43 passed, 6 subtests passed

GitHub handle for tagging: @galpetame

Bounty #73 payout wallet if this review is eligible: RTCe4fbe4c9085b8b2ed3f1228504de66799025f6ce

@saim256
Copy link
Copy Markdown
Author

saim256 commented May 12, 2026

Pushed follow-up commit 580dbda for the non-ASCII admin-key blocker.

What changed:

  • require_admin() now compares UTF-8 encoded bytes with hmac.compare_digest(), so malformed/non-ASCII header values are treated as unauthorized instead of raising TypeError.
  • Added a regression that sends a non-ASCII X-Admin-Key to /api/glitch/disable and asserts the normal 401 unauthorized response.

Validation after the follow-up:

  • python -m pytest issue2288\glitch_system\tests\test_glitch_system.py::TestGlitchAPIAdminAuth tests\test_glitch_api_input_validation.py -q -> 13 passed
  • python -m pytest issue2288\glitch_system\tests\test_glitch_system.py tests\test_glitch_api_input_validation.py -q -> 53 passed on rerun; the first full-suite attempt hit the existing stochastic test_conversation_flow zero-glitch failure, then passed unchanged on rerun
  • python -m py_compile issue2288\glitch_system\src\api.py issue2288\glitch_system\tests\test_glitch_system.py tests\test_glitch_api_input_validation.py -> passed
  • git diff --check -> passed
  • python tools\bcos_spdx_check.py --base-ref origin/main -> OK

Copy link
Copy Markdown
Contributor

@508704820 508704820 left a comment

Choose a reason for hiding this comment

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

Code Review: Require Admin Auth for Glitch Controls

Summary

Fixes #4877's default-allow vulnerability. Now implements default-deny: when GLITCH_ADMIN_KEY is not configured, returns 401 instead of allowing all access.

What Works Well

  1. Default-deny: Fixed the critical vulnerability from #4877
  2. UTF-8 encoding: encode("utf-8") before hmac.compare_digest — more robust
  3. Clear error messages: "GLITCH_ADMIN_KEY not configured" vs "Invalid admin key"

This is the correct fix for #4877

I previously requested changes on #4877 for the default-allow pattern. This PR adopts the correct default-deny approach from #4882.

Remaining concern

Env var naming inconsistency: GLITCH_ADMIN_KEY, MEMORY_ADMIN_KEY, ADMIN_KEY across different PRs. A unified RUSTCHAIN_ADMIN_KEY would be cleaner.

Verdict: Approve ✅

This fixes the critical auth bypass I flagged in #4877.

Copy link
Copy Markdown

@loganoe loganoe left a comment

Choose a reason for hiding this comment

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

Updating my earlier approval: changes are needed. The admin guard passes Flask header strings directly into hmac.compare_digest(). Python raises TypeError when either string contains non-ASCII characters, so a malformed X-Admin-Key can turn the intended 401 into a 500.

Repro:

>>> import hmac
>>> hmac.compare_digest('é', 'secret')
TypeError: comparing strings with non-ASCII characters is not supported

Please normalize to bytes before comparison, for example by encoding both values with UTF-8 or by rejecting non-ASCII input before calling compare_digest(), and add a regression for a non-ASCII admin header.

@saim256
Copy link
Copy Markdown
Author

saim256 commented May 12, 2026

Clarification on the current head 580dbda: this exact non-ASCII compare_digest() issue is already fixed in this commit.

Current code now compares encoded bytes:

if not hmac.compare_digest(
    provided_key.encode("utf-8"),
    expected_key.encode("utf-8"),
):

The regression added in the same commit sends X-Admin-Key: ? to /api/glitch/disable and asserts 401 unauthorized, not 500.

Validation after the fix:

  • python -m pytest issue2288\glitch_system\tests\test_glitch_system.py::TestGlitchAPIAdminAuth tests\test_glitch_api_input_validation.py -q -> 13 passed
  • python -m pytest issue2288\glitch_system\tests\test_glitch_system.py tests\test_glitch_api_input_validation.py -q -> 53 passed on rerun
  • python -m py_compile issue2288\glitch_system\src\api.py issue2288\glitch_system\tests\test_glitch_system.py tests\test_glitch_api_input_validation.py -> passed
  • git diff --check -> passed
  • python tools\bcos_spdx_check.py --base-ref origin/main -> OK

So the requested change is already addressed on the current branch head.

Copy link
Copy Markdown

@idontwantagoldfish83 idontwantagoldfish83 left a comment

Choose a reason for hiding this comment

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

Follow-up on current head 580dbda: the blocker I requested changes for is resolved.

I verified require_admin() now encodes both the provided and expected admin keys to UTF-8 bytes before hmac.compare_digest(), so a non-ASCII X-Admin-Key follows the normal unauthorized path instead of raising TypeError. The new regression also covers this case.

Validation I ran on current head:

  • .venv/bin/python -m pytest issue2288/glitch_system/tests/test_glitch_system.py::TestGlitchAPIAdminAuth tests/test_glitch_api_input_validation.py -q -> 13 passed
  • .venv/bin/python -m py_compile issue2288/glitch_system/src/api.py issue2288/glitch_system/tests/test_glitch_system.py tests/test_glitch_api_input_validation.py -> passed

Copy link
Copy Markdown

@shuibui shuibui left a comment

Choose a reason for hiding this comment

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

Code Review: Solid Fix

Approve. Security pattern is correct.

**Verdict: Approve.

Copy link
Copy Markdown

@shuibui shuibui left a comment

Choose a reason for hiding this comment

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

Code Review: Approve

Good fix.

**Verdict: Approve.

Copy link
Copy Markdown

@shuibui shuibui left a comment

Choose a reason for hiding this comment

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

Code Review: Approve

Good fix. Addresses the issue correctly.

**Verdict: Approve.

Copy link
Copy Markdown

@shuibui shuibui left a comment

Choose a reason for hiding this comment

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

Code Review: Approve

Good fix. Addresses the issue correctly.

**Verdict: Approve.

Copy link
Copy Markdown

@shuibui shuibui left a comment

Choose a reason for hiding this comment

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

Code Review: Approve

Good fix.

**Verdict: Approve.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api API endpoint related BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) size/M PR: 51-200 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Glitch API admin endpoints lack authentication

7 participants