- Status Closed
-
Assigned To
cbay - Private
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.
Loading...
Available keyboard shortcuts
- Alt + ⇧ Shift + l Login Dialog / Logout
- Alt + ⇧ Shift + a Add new task
- Alt + ⇧ Shift + m My searches
- Alt + ⇧ Shift + t focus taskid search
Tasklist
- o open selected task
- j move cursor down
- k move cursor up
Task Details
- n Next task
- p Previous task
- Alt + ⇧ Shift + e ↵ Enter Edit this task
- Alt + ⇧ Shift + w watch task
- Alt + ⇧ Shift + y Close Task
Task Editing
- Alt + ⇧ Shift + s save task
2026-07-14 14-57-01.mkv
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