Security and IDOR
IDOR is enforced only on Core Backend and Middleware Backend. The Vue app is not a security boundary.
The site x-api-key used by the frontend to list public properties is treated as public (it will ship in the browser). Do not recommend “frontend must hide the key” or “frontend must filter owned_by so strangers cannot see data.” If a public key can read or write another user’s booking, fix Core Backend API-key path settings (and Middleware Backend if it proxies). If those settings do not exist yet, recommend adding them on Core Backend/Middleware Backend — not a frontend checklist.
Who implements IDOR
| Layer | Role |
|---|---|
| Core Backend | API-key records: allowed_entities, HTTP method → read|create|update|delete, allowed_request_api_url_path_settings (path wildcards, rate limits, require_user_bearer_token, allowed_user). JWT owned_by / co_owned_by / role must match on writes and private reads. |
| Middleware Backend | Re-check JWT vs booking/property before pay, refund, email, ARI, file-manager. Service key to Core Backend must be server-only, scoped, and must not impersonate another user. Webhooks: PSP signature only. |
| Frontend | How to build the screen: public key for browse, Bearer for logged-in writes. No IDOR implementation task. |
How to build API keys (Core Backend)
Create two keys. Do not give the browser the write key.
Public browse key (in the Vue app)
Allow only public reads, for example:
GET /api/v1/nellalink/smart-meta-manager/entity/property(and slug/uuid if you accept that active listings are public)GET .../entity/roomand.../entity/rate_planfor children of active properties
Deny on this key:
GET/PUT/DELETEbooking,payment,user- All
POST/PUT/PATCH/DELETEentity writes require_user_bearer_token: false is OK for those GET paths only
If Core Backend cannot yet restrict by path, recommend allowed_request_api_url_path_settings on the API-key row (already in Nellalink MiddlewareSecurityUtils). Do not paper over it with frontend filters.
Private / write key (never in the browser)
Used by Middleware Backend (and any trusted server):
require_user_bearer_token: true- Paths for create/update property, room, rate_plan, booking, payment, meta-data, roles
- Server must set
owned_byfrom the JWT, not from a client-chosen uuid
Frontend writes that still go directly to Core Backend (v1 login, create property, create booking) use this pattern: public key is wrong for writes. Ship a second key that requires JWT, or move those writes to Middleware Backend. If Core Backend cannot require JWT per path today, recommend enabling require_user_bearer_token on those paths.
Object rules (Core Backend + Middleware Backend only)
| Object | Public key may | JWT + write key / Middleware Backend may | Must deny |
|---|---|---|---|
property list status=active | Yes | Owner CRUD own | PUT/trash others |
room / rate_plan of an active property | Yes (read) | Owner CRUD | Update others |
booking / payment | No | Owner or property owner | GET/PUT any uuid |
user | No (except own after login) | Own uuid | Other users |
| Refund / email / ARI / upload | No | Middleware Backend + JWT owner | Impersonation |
Known gap
Generic GET .../entity/{type}/{uuid} may return a row to any valid key. Must-fix on Core Backend (ACL or path deny for booking/payment on the public key), or put those reads on Middleware Backend. Not a frontend ticket.
Iteration sign-off (Core Backend + Middleware Backend only)
- [ ] Public browse key cannot read/write bookings, payments, or other users
- [ ] Write paths require JWT;
owned_bymatches token - [ ] Middleware Backend cannot write Core Backend as another user
- [ ] If a control is missing, recommend it on Core Backend path settings or Middleware Backend — do not assign IDOR to frontend