CVE-2026-126642: Awx: webhook credential assignment omits use_role check, exposing another user's token
An incorrect authorization flaw was found in AWX, the automation controller component of Red Hat Ansible Automation Platform. The API access classes for JobTemplate and WorkflowJobTemplate do not check the caller's Credential userole when assigning the single-valued webhookcredential foreign key: JobTemplateAccess.canadd/canchange and WorkflowJobTemplateAccess.canchange in awx/main/access.py omit the checkrelated('webhookcredential', Credential, ..., rolefield='userole') call that UnifiedCredentialsMixin.canattach performs for the normal many-to-many credentials relationship, and the serializer validates only the credential's type and namespace. A user who may administer their own job template (or workflow job template) and use its project and inventory can therefore attach a webhook token credential (for example a GitLab token) that they do not have use permission on. The template administrator can retrieve the template's webhook key; a subsequent webhook event causes AWX to decrypt the attached token and send it in the request header (for GitLab, PRIVATE-TOKEN) to a status URL derived from the event payload, disclosing the victim's token to a destination the attacker can influence. This may disclose another user's personal access token and allow whatever actions that token permits.
Other sources
The API access classes for JobTemplate and WorkflowJobTemplate do not check the caller's Credential userole when assigning the single-valued webhookcredential foreign key. The serializer checks only that this credential is a token for the selected webhook service. A user who may administer their own template and use its Project and Inventory appears able to attach a GitLab token credential that they are not allowed to use. The template's webhook key is available to that administrator. A GitLab webhook event then causes AWX to decrypt the attached token and send it in the PRIVATE-TOKEN header to the event-derived status URL. Confirmed in source for release tag 24.6.1 and devel commit 8565291e43e17cd1ee5333e82e57aeb230e6574e. Source-level root cause: (1) awx/api/permissions.py ModelAccessPermission.checkputpermissions delegates the PATCH authorization decision to JobTemplateAccess.canchange or WorkflowJobTemplateAccess.canchange. (2) awx/main/access.py JobTemplateAccess.canadd and canchange check the caller's permissions on the template, Project, Inventory and Execution Environment, but do not call checkrelated('webhookcredential', Credential, ..., rolefield='userole'); WorkflowJobTemplateAccess.canchange has the same omission, whereas UnifiedCredentialsMixin.canattach enforces userole for the normal many-to-many credentials relationship. (3) awx/api/serializers.py JobTemplateMixin.validate checks webhookcredential.credentialtype.kind and namespace but not caller authorization for that Credential. (4) awx/api/views/webhooks.py WebhookKeyView.get returns a template's webhook key to its administrator; GitlabWebhookReceiver authenticates with that key then constructs a status URL from request.data['project']['weburl']; WebhookReceiverBase.post copies obj.webhookcredential and the status URL into the new job before signalstart. (5) awx/main/models/mixins.py WebhookMixin.updatewebhookstatus decrypts and sends the token. Reporter notes they verified the permission branch and outbound header construction by executing functions extracted from the official source snapshots and sent a dummy token to a loopback receiver through updatewebhookstatus; they did not deploy a full AWX instance.
— Red Hat