# Avo: Missing Authorization in Avo Association Attach Endpoint Allows Unauthorized Relationship Manipulation and Privilege Escalation

Avo's association attach POST endpoint skips the attach_<association>? policy check applied to the form, letting low-privileged users attach arbitrary related records and escalate privileges.

- Payout: Research
- Severity: critical
- Program: Avo
- Found by: xIllunight
- Disclosed: 2026-06-17
- CVE: CVE-2026-55518
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-8fq9-273g-6mrg
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-8fq9-273g-6mrg
- Tags: area:web domain:web impact:integrity impact:privesc kind:research platform:ghsa sev:critical tech:ruby technique:source-review vuln:access-control vuln:auth-bypass vuln:idor vuln:privilege-escalation

**Target:** Rails admin panel association attach endpoint (POST /resources/:resource/:id/:related)
**Root cause:** The authorize_attach_action before_action is bound only to the `new` form action, not the mutating `create` action, so attach_<association>? policies are never enforced on the write path.
**Steps:**
1. Authenticate to Avo as a low-privileged user with a policy denying `attach_users?` (returns false).
2. Confirm the form path is blocked: `GET /admin/resources/projects/1/users/new`.
3. Send the write request directly: `POST /admin/resources/projects/1/users` with body `authenticity_token=<CSRF>&fields[related_id]=42`.
4. Observe the related record is attached despite the denied policy.
**How found:** Noticed the attach authorization callback was registered only for `new` while the mutating `create` action had no attach check, unlike the detach path which authorizes `destroy`.
**Exploitation:** An authenticated low-privileged Avo user sends a crafted POST to the association create route with fields[related_id] set to a target record ID, bypassing the hidden/disabled attach control and mutating the association (e.g. attaching user 42 to project 1).
**Escalation:** Attaching users to admin groups, privileged projects, tenants, roles or memberships yields privilege escalation and cross-tenant data exposure where associations drive authorization.
**Insight:** When a framework splits a form-render action from the write action, verify the authorization before_action covers the mutating verb, not just the GET that renders the form; compare sibling actions (detach authorizes destroy) to spot the asymmetry.

## Proof of concept (copied exactly from the original report)

**Direct POST attach bypassing policy**

```
POST /admin/resources/projects/1/users
Content-Type: application/x-www-form-urlencoded

authenticity_token=<CSRF>&fields[related_id]=42
```

**PoC script confirm-attach invocation**

```
python poc_avo_association_attach_bypass.py \
  --base-url http://localhost:3000 \
  --avo-root /admin \
  --cookie "_app_session=<LOW_PRIVILEGED_SESSION_COOKIE>" \
  --parent-resource projects \
  --parent-id 1 \
  --related-name users \
  --related-id 42 \
  --confirm-attach
```

