# Frontend security rules for enterprise apps

Source: https://tt-tech.io/blog/frontend-security-enterprise-untrusted-client
For Angular and React frontends. Add to AGENTS.md or save as a skill. Your project's own rules win where they differ.

## Rules

1. The browser is untrusted. Every access rule and business limit is enforced on the server. A check in a component is only for the user's screen.
2. When you add a client-side check (a limit, a role, a permission), add or find the same check on the server in the same change. If there is none, report it as a finding.
3. Take roles and permissions from the server's answer. Never decide what the user may do by decoding a token in the client.
4. Route guards are for navigation, not protection. Put `canActivateChild` on the parent route of an area, use `canMatch` for role-based variants of a path, and still expect the server to refuse.
5. Hide actions a role never has. Disable, with the reason shown, actions the user could have later (a limit, a missing signature).
6. Keep the sanitizer on. Never call `bypassSecurityTrust*` (Angular) or use `dangerouslySetInnerHTML` (React) on data from a user or an API. If some markup is wanted, map an allowed subset to elements in the template.
7. Never store session ids or tokens in `localStorage` or `sessionStorage`. Use an `httpOnly` cookie session through a backend for frontend, or a short-lived token in memory when the API is shared with other clients.
8. With cookie sessions, keep CSRF protection on: in Angular, `HttpClient` sends the `XSRF-TOKEN` cookie back as an `X-XSRF-TOKEN` header, and the server must check it.
9. No secrets in client code: no API key, token or password in the frontend, not even temporarily. Everything shipped to the browser is public.
10. The browser never calls a third-party service directly. The backend holds the key and makes the call.
11. Treat the Content Security Policy as a second layer: nonces when a server renders each response, `autoCsp` hashes when the app is static files. Do not loosen it to make a script run.
12. Never log tokens, session ids, passwords, personal data or bank and card data from the client. Mask them or leave them out. Send an interaction id with each request instead, so server logs can be matched.

## Before you say done

- Search the diff for `bypassSecurityTrust`, `dangerouslySetInnerHTML`, `localStorage` and strings that look like keys. Remove each hit or explain it in the pull request.
- For every client-side rule in the diff, name the server code that enforces it.
- List what you checked and what you could not check.
