Bug 2571729 (CVE-2026-126642)
| Summary: | CVE-2026-126642 awx: webhook credential assignment omits use_role check, exposing another user's token | ||
|---|---|---|---|
| Product: | [Other] Security Response | Reporter: | OSIDB Bzimport <bzimport> |
| Component: | vulnerability | Assignee: | Product Security <prodsec-ir-bot> |
| Status: | NEW --- | QA Contact: | |
| Severity: | medium | Docs Contact: | |
| Priority: | medium | ||
| Version: | unspecified | CC: | jlanda, kshier, rbobbitt, simaishi, stcannon, yguenane |
| Target Milestone: | --- | Keywords: | Security |
| Target Release: | --- | ||
| Hardware: | All | ||
| OS: | Linux | ||
| Whiteboard: | |||
| Fixed In Version: | Doc Type: | --- | |
| Doc Text: |
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 use_role when assigning the single-valued webhook_credential foreign key: JobTemplateAccess.can_add/can_change and WorkflowJobTemplateAccess.can_change in awx/main/access.py omit the check_related('webhook_credential', Credential, ..., role_field='use_role') call that UnifiedCredentialsMixin.can_attach 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.
|
Story Points: | --- |
| Clone Of: | Environment: | ||
| Last Closed: | Type: | --- | |
| Regression: | --- | Mount Type: | --- |
| Documentation: | --- | CRM: | |
| Verified Versions: | Category: | --- | |
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
| Cloudforms Team: | --- | Target Upstream Version: | |
| Embargoed: | |||
The API access classes for JobTemplate and WorkflowJobTemplate do not check the caller's Credential use_role when assigning the single-valued webhook_credential 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.check_put_permissions delegates the PATCH authorization decision to JobTemplateAccess.can_change or WorkflowJobTemplateAccess.can_change. (2) awx/main/access.py JobTemplateAccess.can_add and can_change check the caller's permissions on the template, Project, Inventory and Execution Environment, but do not call check_related('webhook_credential', Credential, ..., role_field='use_role'); WorkflowJobTemplateAccess.can_change has the same omission, whereas UnifiedCredentialsMixin.can_attach enforces use_role for the normal many-to-many credentials relationship. (3) awx/api/serializers.py JobTemplateMixin.validate checks webhook_credential.credential_type.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']['web_url']; WebhookReceiverBase.post copies obj.webhook_credential and the status URL into the new job before signal_start. (5) awx/main/models/mixins.py WebhookMixin.update_webhook_status 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 update_webhook_status; they did not deploy a full AWX instance.