Skip to content

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

LayerRole
Core BackendAPI-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 BackendRe-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.
FrontendHow 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/room and .../entity/rate_plan for children of active properties

Deny on this key:

  • GET/PUT/DELETE booking, payment, user
  • All POST / PUT / PATCH / DELETE entity 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_by from 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)

ObjectPublic key mayJWT + write key / Middleware Backend mayMust deny
property list status=activeYesOwner CRUD ownPUT/trash others
room / rate_plan of an active propertyYes (read)Owner CRUDUpdate others
booking / paymentNoOwner or property ownerGET/PUT any uuid
userNo (except own after login)Own uuidOther users
Refund / email / ARI / uploadNoMiddleware Backend + JWT ownerImpersonation

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_by matches 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

API-first. Middleware Backend wins over Core Backend when both exist.