Skip to content

fix: add authorization checks to XML-RPC stop() endpoints#282

Open
Zinkelburger wants to merge 1 commit intobeaker-project:python-3from
Zinkelburger:fix/xmlrpc-stop-authz-bypass
Open

fix: add authorization checks to XML-RPC stop() endpoints#282
Zinkelburger wants to merge 1 commit intobeaker-project:python-3from
Zinkelburger:fix/xmlrpc-stop-authz-bypass

Conversation

@Zinkelburger
Copy link
Copy Markdown

@Zinkelburger Zinkelburger commented Apr 12, 2026

Summary

The XML-RPC methods jobs.stop(), recipesets.stop(), recipes.stop(), and recipetasks.stop() only require authentication (identity.not_anonymous()) but do not verify that the caller owns the job or has the stop_task permission. This allows any authenticated user to cancel any other user's job by calling these endpoints directly, bypassing the can_stop() check enforced by the user-facing taskactions.stop() and the REST API (POST /jobs/<id>/status).

Proof

Tested non-destructively against beaker.engineering.redhat.com using a finished job (J:12143204) owned by lzachar, called as anbernal:

STEP 1: taskactions.stop('J:12143204', 'cancel', ...)
  Response: FAULT — You don't have permission to cancel J:12143204

STEP 2: jobs.stop(12143204, 'cancel', ...)
  Response: SUCCESS (returned without error)

Same user, same job — taskactions.stop correctly denies access while jobs.stop allows it through. Since the target job was already finished, cancel() was a no-op and no state was modified.

Fix

Adds can_stop(identity.current.user) checks to all four endpoints, matching the authorization already present in taskactions.stop(). Lab controllers are unaffected because they authenticate with the stop_task permission, which can_stop() already permits.

Files changed

  • Server/bkr/server/jobs.pyJobs.stop()
  • Server/bkr/server/recipesets.pyRecipeSets.stop()
  • Server/bkr/server/recipes.pyRecipes.stop()
  • Server/bkr/server/recipetasks.pyRecipeTasks.stop()
  • IntegrationTests/.../test_job_cancel_authz.py — regression tests for all four endpoints

@packit-as-a-service
Copy link
Copy Markdown

Failed to load packit config file:

Cannot parse package config. ValidationError({'jobs': {0: {'packages': defaultdict(<class 'dict'>, {'beaker': {'value': {'synced_files': ['Unknown field.']}}})}, 1: {'packages': defaultdict(<class 'dict'>, {'beaker': {'value': {'synced_files': ['Unknown field.']}}})}, 2: {'packages': defaultdict(<class 'dict'>, {'beaker': {'value': {'synced_files': ['Unknown field.']}}})}}, 'packages': defaultdict(<class 'dict'>, {'beaker': {'value': {'synced_files': ['Unknown field.']}}})})

For more info, please check out the documentation or contact the Packit team. You can also use our CLI command config validate or our pre-commit hooks for validation of the configuration.

@Zinkelburger Zinkelburger force-pushed the fix/xmlrpc-stop-authz-bypass branch 3 times, most recently from 135ce1d to 0e695ed Compare April 12, 2026 21:27
@JohnVillalovos
Copy link
Copy Markdown
Collaborator

You probably want to target the python-3 branch.

The XML-RPC methods jobs.stop(), recipesets.stop(), recipes.stop(),
and recipetasks.stop() only required authentication (not_anonymous)
but did not verify that the caller owns the job or has the stop_task
permission.  This allowed any authenticated user to cancel any other
user's job by calling these endpoints directly, bypassing the
can_stop() check enforced by taskactions.stop().

Add can_stop(identity.current.user) checks to all four endpoints,
matching the authorization already present in taskactions.stop() and
the REST API (POST /jobs/<id>/status).  Lab controllers are
unaffected because they authenticate with the stop_task permission,
which can_stop() already permits.

Made-with: Cursor
@Zinkelburger Zinkelburger force-pushed the fix/xmlrpc-stop-authz-bypass branch from 0e695ed to 53dbff1 Compare April 12, 2026 21:31
@Zinkelburger Zinkelburger changed the base branch from master to python-3 April 12, 2026 21:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants