OutSystems Security Specialist common mistakes
OutSystems Security Specialist · Understand the traps and how to avoid them.
Treating the built-in Users entity as a place to store application-specific profile and permission data, then wondering why role assignments do not behave as expected.
Candidates see that Users is a system entity with Id, Username, and Email, and assume it is a general-purpose user table. In reality it is owned by the platform, its records are managed by the user provider, and modifying it directly can desynchronise authentication from the identity store.
What to do instead
Keep Users read-only in application logic. Create a separate Profile entity with a one-to-one reference to User Id for business attributes, and derive permissions from Roles plus your own authorization tables. Use the platform's user management screens or the Users API for lifecycle operations.
Choosing an external identity provider for end users but forgetting to configure the login redirect URIs and the callback URL in the provider, then debugging the resulting error inside Service Studio.
Candidates focus on the OutSystems-side configuration (IdP metadata, client ID, secret) and treat the provider-side registration as an afterthought. OAuth/OIDC flows fail closed at the provider before any OutSystems log appears, so the platform shows only a generic authentication error.
What to do instead
Register the exact callback URL the platform generates for each environment (dev, test, production) in the identity provider, including scheme and trailing path. Verify the client is enabled for the authorization code flow with PKCE where supported, and check provider-side logs first when login fails.
Assuming that hiding a screen or menu item from a role is an access control measure, so a user who cannot see the link also cannot reach the screen by typing its URL.
The visual editor makes it easy to gate menu entries by role and candidates conflate that UI-level gating with server-side authorization. Screen visibility is a rendering decision; the request still reaches the screen action unless the screen itself checks authorization.
What to do instead
Enforce authorization on the screen or its preparation, not only in the menu. Use the screen's role-based access property or an explicit check in the preparation that raises a security exception, and apply the same rule in every exposed screen action and service action.
Relying on entity-level CRUD permissions (Create, Read, Update, Delete) as the whole authorization model for a multi-tenant or multi-role application.
Entity permissions are coarse: they say which roles may perform an operation on the entity type, not which rows. Candidates who stop there ship applications where any user in a role can read or modify any record, including other tenants' data.
What to do instead
Add row-level filtering in queries (for example by tenant or owner reference) and validate ownership in every server action before writing. Treat entity permissions as a first line of defence and explicit data-scope checks as the second.
Leaving a REST or SOAP expose action public because it is 'only called by our own mobile app', without verifying the caller's identity or the integrity of the request.
Candidates mentally model the mobile client as trusted and assume the endpoint is hard to discover. Exposed service actions are reachable by anyone who learns the URL, and mobile binaries can be inspected to recover endpoints and any embedded secrets.
What to do instead
Require authentication on exposed actions, validate the caller's permissions on each request, and never embed long-lived secrets in client code. Where a public endpoint is genuinely needed, apply rate limiting, input validation, and a token or signature scheme with short lifetimes.
Judging a connection as secure because HTTPS is enabled, while the application still calls internal services over plain HTTP or disables certificate validation to make an integration work.
Candidates equate the browser-facing padlock with end-to-end security. Integration Studio and the platform's HTTP client defaults are easy to loosen, and turning off certificate validation is a tempting quick fix for a self-signed internal endpoint.
What to do instead
Enforce HTTPS on all external and internal hops, keep certificate validation on, and install the issuing CA in the trust store rather than bypassing validation. Audit integrations for hard-coded http:// endpoints and for settings that skip hostname or certificate checks.
Configuring TLS but leaving weak protocol versions or cipher suites enabled, or accepting the platform default without checking it against the environment's requirements.
Candidates treat TLS as a binary on/off setting and do not think about version negotiation. Legacy clients and internal appliances often force older protocols, and the path of least resistance is to allow them.
What to do instead
Restrict to TLS 1.2 and 1.3, disable SSL and TLS 1.0/1.1, and review the cipher list against current guidance. Test with a protocol scanner per environment, and document any exception with an owner and an expiry date.
Storing passwords, API keys, or personal data in a plain text entity attribute or in a Site Property because encryption 'slows things down' or seems complicated.
Candidates reach for the simplest data model and do not distinguish between data that must be hashed (passwords), data that must be encrypted and retrievable (keys, tokens), and data that must be minimised (personal data). Platform password storage is handled for you, which can create the false impression that all sensitive fields are.
What to do instead
Never store passwords yourself; use the platform's authentication. For secrets, use the platform's secure configuration and secret-management facilities rather than Site Properties. For sensitive business attributes, encrypt at rest with a managed key, and avoid storing personal data you do not need.
Logging full request and response payloads, including tokens and personal data, to help with debugging and leaving that logging enabled in production.
Candidates want observability and add verbose logging during development. Logs are widely readable, often shipped to third-party systems, and rarely reviewed for sensitive content, so the debugging aid becomes a data leak.
What to do instead
Log identifiers and outcomes, not payloads. Redact or omit tokens, passwords, and personal data at the logging call site, set log levels per environment so verbose logging is off in production, and include log retention and access review in the security checklist.
Treating input validation as a client-side concern, relying on form field validation in the UI and passing values straight into queries, expressions, or external calls on the server.
Candidates see validation rules in the screen editor and assume they are enforced everywhere. Screen validations run in the browser and are bypassed by direct service calls, and platform query builders do not protect against every injection vector in raw SQL or dynamic expressions.
What to do instead
Validate on the server in the action or service layer, using typed inputs, allow-lists, and length and range checks. Use parameterised queries and avoid concatenating user input into SQL or expressions. Keep client-side validation for usability, not security.