
Grafana OSS 13.2.3 - High - Remote - Invite join - SignUpStep2 joins pending org invites without the code
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · grafana-signup-invite-join
Class: Privilege leftover Reach: Remote
Grafana OSS 13.2.3 (6193dc0) - Grafana Labs
When users.allow_sign_up is true and users.verify_email_enabled stays at the default false, unauthenticated POST /api/user/signup/step2 with an invited email creates the account and applyUserInvite attaches every InvitePending row for that address at invite.Role. The 30-character invite code is never required on this path. Role can be Admin.
Know the invited email. Skip the invite code. Join the org as Admin.
| ID | no CVE yet |
| Class | Privilege leftover |
| Reach | Remote (unauthenticated HTTP; needs users.allow_sign_up=true) |
| CWE | CWE-862 |
| CVSS | High: 8.1 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N |
| Product | Grafana OSS |
| Affected | 13.2.3 (6193dc0); open-signup path |
| Auth | unauthenticated. Email verify default off. Signup off in stock defaults.ini. |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 only |
Needs the invited address (the invite email, a guess, or another leak). Does not need the mailbox and does not need the invite code. Does not need an existing Grafana account.
| Privilege | Method / sink | Recon / integrity / availability | Lab-proven or inferred |
|---|---|---|---|
| Create an account as the invited email | Unauth POST /api/user/signup/step2 with code="" | Integrity (account create) | Lab-proven. Session /api/user login=invitee |
| Join the invited org at the invite role (Admin in this lab) | applyUserInvite from GetTempUsersQuery{Email, InvitePending} | Integrity (org membership + role) | Lab-proven. /api/user/orgs role=Admin; sqlite org_user Admin |
| Complete the pending invite so the real invitee cannot use it | updateTempUserStatus(..., TmpUserCompleted) | Integrity (invite consumption) | Lab-proven. Pending list empty; sqlite temp status=Completed |
| Same join for Viewer/Editor invites | invite.Role is copied as-is | Integrity | Inferred. Lab used Admin |
| Read/write that org as Org Admin after login | Org Admin APIs (datasources, dashboards, users) | Recon + integrity | Inferred. Lab stops at role=Admin |
| Negative control | Signup as a different email with empty code | n/a | Lab-proven. invite-org-role=none |
Closed on this leftover: default install with signup off; email-verify-on path (that path checks form.Code); complete-invite email bind (CVE-2022-39306 class, still present); Grafana Admin (isGrafanaAdmin). Not unauthenticated RCE. Skip Grafana G2 (IAM SSOSetting k8s authorizer).
I pinned Grafana OSS 13.2.3. Default OSS came back empty at this bar. I sat on the open-signup path anyway. POST /api/user/signup/step2 is unauthenticated. SignUpStep2 creates the user, then loads pending invites by email. form.Code is only required when VerifyEmailEnabled is true.
Wrong turns already recorded: re-filing CVE-2022-39306 (complete-invite still binds the email); treating stock defaults.ini as this leftover (signup is off there); SCIM unauth on OSS (nil k8s client); a reverse shell. Theatre.
python3 grafana-signup-invite-join-Abraxas-Labs.py
or:
cd lab
./run.sh
Target only http://127.0.0.1:19350. Image grafana/grafana:13.2.3 with GF_USERS_ALLOW_SIGN_UP=true and email verify left off.
SUCCESS GRAFANA-SIGNUP-INVITE-JOIN version=13.2.3 invite-org=2 invite-code-len=30 step2-code-sent=empty step2-redirect=redirect-to-select-org api-role=Admin sqlite-role=Admin temp-status=Completed control-invite-org-role=none GRAFANA-SIGNUP-INVITE-JOIN-WITNESS
Require the pending invite code, or mailbox proof, before applyUserInvite on signup. Do not attach InvitePending rows from email match alone.
signup.go · org_invite.goGNU Affero GPL v3.0. See LICENSE. Loopback lab only. No warranty.