Skip to content

security(star-rating): authorize the /o?method=star ratings read (24.05) - #7956

Merged
shepardly[bot] merged 6 commits into
release.24.05from
backport/star-method-authorize-2405
Aug 27, 2026
Merged

security(star-rating): authorize the /o?method=star ratings read (24.05)#7956
shepardly[bot] merged 6 commits into
release.24.05from
backport/star-method-authorize-2405

Conversation

@ar2rsawseen

Copy link
Copy Markdown
Member

Backport of #7955 to release.24.05.

/o?method=star returns the platform and application-version combinations that have received star ratings, and performed no authorization — any caller supplying an app_id received that application's data with no api_key, no auth_token and no session, while the sibling /o/feedback/data correctly answers 400 Missing parameter "api_key" or "auth_token" on the identical credential-less request.

Authentication on /o is per method, not global: core methods call validateUserForDataReadAPI themselves, and the default: branch hands the validators to plugins as helpers without calling them, so a plugin that claims a request must authorize it. This branch claimed the request, returned true, and never called a validator.

Fix (identical to #7955): wrap the branch in validateRead(params, FEATURE_NAME, …), the same check the sibling reads in this file already apply, running before the period parameter is validated so an unauthorized caller cannot probe the endpoint through its error responses. The diff is mostly re-indentation from introducing the callback.

The only caller is the dashboard Ratings page (starRatingPlugin.requestPlatformVersion), which sends the session credential and an app the member has access to, so it is unaffected. eslint clean.

🤖 Generated with Claude Code

Backport of #7955 to release.24.05.

The star-rating dashboard read performed no authorization. Authentication on /o is
per method: core methods call validateUserForDataReadAPI themselves, and the default
branch hands the validators to plugins as helpers without calling them, so a plugin
that claims a request must authorize it. This branch claimed the request and never
did, so it answered callers with no account, token or session, for any app_id.

Wrap it in validateRead(params, FEATURE_NAME, ...), the same check the sibling reads
in this file already apply, running before the period parameter is validated so an
unauthorized caller cannot probe the endpoint. The only caller is the dashboard
Ratings page, which sends the session credential, so it is unaffected.

Reported through the security bug bounty programme (received 2026-08-18).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread plugins/star-rating/api/api.js
result[data[0]] === undefined is not a "have I seen this platform" test on a plain object.
The platform name comes off the public star-rating event, in the platform_version_rate
segmentation, so anyone who can write to the app chooses it, and "__proto__",
"constructor", "toString", "valueOf" and "hasOwnProperty" all read back as inherited
members rather than as undefined. The array is then never created and the next line throws

    TypeError: result[data[0]].indexOf is not a function

so one planted row denies the whole read for every authorized caller until it ages out.
Verified by running the loop, not by reading it.

Built with Object.create(null) instead. Nothing else changes: the keys are still ordinary
strings, and JSON.stringify serialises a null prototype object identically, which is what
returnOutput does with it. The platform has a second accumulator in the granular branch
and it gets the same treatment.

Tests lift both the accumulator's declaration and the loop out of the real source, so the
choice of object is what is under test rather than one the test made for itself. Four of
the five fail against the previous code, with the TypeError above.
The changelog is generated from PR and commit titles later, so an entry written by hand
here is duplicated work at best. It is also the single worst file in this wave for
conflicts: every merge to the base appends a line, which re-conflicts every open branch
that also appends one. Eight of the sixteen conflicts across these security PRs today
were this file and nothing else, and two of them came back within the hour.

Only the lines this branch added are removed - the file is otherwise the base's, and the
change here was purely additive, so nothing else moves.
@shepardly
shepardly Bot enabled auto-merge August 27, 2026 16:23
@shepardly
shepardly Bot merged commit 386fd76 into release.24.05 Aug 27, 2026
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants