Security vulnerabilities

  • Status Closed
  • Assigned To
    cbay
  • Private
Attached to Project: Security vulnerabilities
Opened by vikas0vks - 14.07.2026
Last edited by cbay - 14.07.2026

FS#408 - API bypasses Databases feature entitlement (create plan-restricted DBs)

Severity

Medium — CVSS 3.1 5.4 (AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N) — broken authorization / plan-restriction bypass.

Summary

On an account where the Databases feature is not enabled, the administration interface correctly blocks database creation with "Feature unavailable — This feature is currently not available for this account." However, the REST API (POST /v1/database/) does not perform the same entitlement check and returns 201 Created. The resulting MySQL/MariaDB (and PostgreSQL) database is fully functional and reachable on mysql-<account>.alwaysdata.net. The plan restriction is enforced only in the UI, not server-side in the API.

Steps to reproduce

Step 1 — The UI enforces the entitlement (feature is genuinely gated). Request:

GET /database/add/ HTTP/2
Host: admin.alwaysdata.com
Cookie: sessionid=<your admin session>

Response:

HTTP/2 200 OK
Content-Type: text/html

<h1>Feature unavailable</h1>
<p>This feature is currently not available for this account.
   Please contact us if you want to activate it.</p>

Step 2 — The API bypasses the entitlement. Request:

POST /v1/database/ HTTP/2
Host: api.alwaysdata.com
Authorization: Basic <API-TOKEN account=YOUR-ACCOUNT>
Content-Type: application/json

{"name":"YOUR-ACCOUNT_qz","type":"MYSQL"}

Response:

HTTP/2 201 Created
Location: /v1/database/<id>/
Content-Length: 0

Step 3 — The database exists and is fully functional. Request:

GET /v1/database/ HTTP/2
Host: api.alwaysdata.com
Authorization: Basic <API-TOKEN account=YOUR-ACCOUNT>

Response:

HTTP/2 200 OK
Content-Type: application/json

[{"id":<id>,"name":"YOUR-ACCOUNT_qz","type":"MYSQL","href":"/v1/database/<id>/","permissions":{"YOUR-ACCOUNT":"FULL"}}]

The database accepts real connections (a default DB user exists; its password is set via PATCH /v1/database/user/<id>/):

$ mysql -h mysql-<account>.alwaysdata.net -u <account> -p***** -e "SELECT CURRENT_USER(), VERSION(); SHOW DATABASES;"
<account>@%    11.4.12-MariaDB
information_schema
<account>_qz

Step 4 (optional) — Confirms the gate is real, not a transient UI state. DELETE /v1/database/<id>/ returns 204. Reloading GET /database/add/ again returns the "Feature unavailable" page, so the account genuinely lacks the entitlement; only the API fails to enforce it.

Reproduced multiple times. The same bypass also works for "type":"POSTGRESQL" (also plan-gated), so it is not engine-specific. My API token is omitted from this public report and can be provided privately if needed.

Impact

A customer whose plan does not include the Databases feature can create and use functional MySQL/MariaDB and PostgreSQL databases through the API, obtaining a resource their plan does not permit. The entitlement check is missing on the server side (API) and enforced only in the UI, allowing the restriction to be bypassed programmatically.

Remediation

Enforce the account's feature entitlements server-side on the API resource-create endpoints (POST /v1/database/ and any other plan-gated resource), returning the same "feature not available for this account" rejection that the UI applies.

Closed by  cbay
14.07.2026 10:45
Reason for closing:  Invalid
Admin
cbay commented on 14.07.2026 10:45

Hello,

The URL you're using (/database/add/) is invalid and never used as-is in the administration interface as it's missing the mandatory 'type' GET parameter.

The error message ("Feature unavailable") is returned in such cases. But the account is actually not missing any feature at all, which is why the API request does succeed.

Kind regards,
Cyril

Loading...

Available keyboard shortcuts

Tasklist

Task Details

Task Editing