The /api/post-contribution route of the ISA Toolforge tool combines several antipatterns:
- It doesn’t have any CSRF protection, as far as I can see: there’s no kind of edit token in the request data, nor does it check where the request comes from.
- The parameters of the API call made to the MediaWiki Action API are part of the request data (generated by the ISA JavaScript code in the benign case, but otherwise attacker-controlled), the Python backend mainly adds a valid CSRF token.
- It’s registered not only for the POST method, but also for GET. (But it also only reads only the request body, not the URL, so I don’t think it can actually be exploited over GET.)
Issue 1 means that if a user is logged into ISA, any website they visit can post contributions on their behalf. Issue 2 means that the contributions are not limited to the kinds of edits that the tool is supposed to make, but that any API action is available, as long as it a) uses the default csrf token type (unlike e.g. the rollback API), and b) is covered by the grants of the tool’s OAuth consumer (Interact with pages: Edit existing pages; Create, edit and move pages).
Example:
fetch('https://isa.toolforge.org/api/post-contribution', { method: 'POST', mode: 'cors', credentials: 'include', body: JSON.stringify([{ campaign_id: 0, image: null, edit_action: null, edit_type: null, country: null, api_options: { action: 'edit', title: 'User:Lucas Werkmeister/sandbox', appendtext: 'Hi :)', }, }]), });
I ran this code on tmp.lucaswerkmeister.de (an arbitrary website which conveniently has no connect-src CSP that might block this request), and an edit was made.
Issues 1 and 3 also seem to affect several other APIs of the tool (e.g. creating or updating a campaign), but I haven’t bothered checking if those APIs are actually vulnerable.