skip to content

In a single-page trading app whose trader-vs-supervisor route guard ships in downloaded JavaScript, where does the trust boundary actually belong?

level: middleimportance: should knowfreq 58%

answer

  1. who runs the code decides
  2. the browser is the user's machine
  3. shipped guards are advisory
  4. one zone past the response
  5. first enforcing point is the API

basics

~20 s

The boundary belongs at the server API, not inside the browser. Everything you ship - route guards, hidden buttons, role flags - runs on a machine the user controls, so both roles sit in one untrusted zone.

solid answer

~50 s

Once the bundle is delivered, the browser is the user's machine: they can edit runtime state, skip the guard in a debugger, or ignore the app entirely and call the API from a script. So a boundary drawn between "trader view" and "supervisor view" inside that bundle claims an enforcement you do not have. On the corrected diagram the whole browser - both roles, all client state - is one untrusted zone, and the boundary sits on the flow into the server API, where the role decision is actually made and logged. The adversary this surfaces is not an outsider stealing a session; it is an authenticated low-privilege trader with a valid token calling approval endpoints, so the asset at risk is order integrity and money. Keep the client guard as user experience, annotated non-enforcing so no later reviewer mistakes it for a control.

go deeper

for a junior

Know that anything shipped to a browser can be read and changed by the user, so a check written in client code cannot be relied on to keep two roles apart.

for a middle

Explain the mechanics: after delivery the user owns the runtime, can bypass the guard or call the API directly, so the whole client collapses into one untrusted zone on the diagram and the boundary moves to the server.

for a senior

Show how the reframing changes the threat list - the adversary becomes an authenticated insider with a valid token - and say what you write on the diagram so the non-enforcing guard is never mistaken for a control.

for a principal

Own the convention: how your organisation records unenforceable boundaries, and how you stop teams shipping designs whose only role separation lives in a component the customer controls.

## The mistake A team models their trading front end. The single-page app has two personas - a trader who can enter orders, and a desk supervisor who can approve orders above a limit - and the router refuses to render the approval screens unless the logged-in user's role claim says supervisor. On the diagram, someone draws a trust boundary between the trader part of the app and the supervisor part, both inside the browser box. It looks tidy, and it is wrong in a way that hides the most likely attack on the system. ## Why a boundary cannot live inside code you ship A trust boundary is only meaningful where an enforcement point you control sits at the crossing. Once the server has answered with a bundle, execution moves to hardware, an operating system, a browser and a set of extensions and developer tools that belong to the user. On that side the user can: change in-memory state so the role flag reads supervisor, set a breakpoint and step past the guard, load a patched bundle, or drop the app completely and send requests with a scripted client. Nothing in the delivered code observes any of this, and nothing reports it. So from the server's point of view the browser is **one zone**, not two. The trader and supervisor "zones" the diagram drew are two arrangements of pixels inside the same untrusted process. Delivering that bundle over TLS does not change it: transport integrity protects the code in flight, not its execution afterwards. Neither does minification or obfuscation - those raise effort, not authority, and an attacker does not need to read the guard to bypass it when they can call the endpoint the guard was hiding. ## What the corrected diagram looks like Draw one boundary between the browser (everything in it, both roles, session storage included) and the server API. Then the crossings you enumerate are the API calls, and the questions become the right ones: - Which endpoints does an *authenticated trader* reach if they simply send the request the supervisor UI would have sent? Every one of them is an elevation-of-privilege candidate until the server re-decides the role on its own authority. - What fields does the client supply that the server should be deriving instead - the acting role, the desk, the approval limit, the identity of the approver? - What does the audit record say if the client is lying about who approved what? Non-repudiation depends on the server writing what it decided, not what the client claimed. The client guard still belongs on the diagram, but annotated as **non-enforcing / UX only**. That annotation is doing real work: diagrams outlive the people who drew them, and the next reviewer who sees a line and no caveat will assume the split is enforced and skip the very threats it fails to stop. ## The adversary this reframing exposes The original diagram implicitly modeled an outsider - someone who must first steal a session to reach anything. The corrected one puts the *legitimate authenticated user* on the untrusted side, which is where the interesting attack lives here: a trader holding entirely valid credentials, approving their own oversized order or raising their own limit. Nothing about that request is anomalous at the transport or session layer, so the only place it can be stopped is a server-side decision at the crossing. Note also the direction the asset sits in: money and order integrity, not confidentiality of customer data - so the threats that dominate are tampering and elevation of privilege, and the control that matters is a server-side decision plus an audit trail the client cannot influence. ## The general rule to state The moment code or data crosses to a party you do not control, you cannot place another boundary beyond it. Every enforcement point must be on your side of the last crossing. This generalises past browsers to any component you hand out: a partner's batch job you deliver, an on-premises agent installed in a customer's estate, a widget embedded in someone else's page. In each case the diagram may show internal structure for clarity, but only the flow back into a system you operate can carry a boundary. ## What good answers add Strong candidates also say what the client-side guard is *for*: it stops honest users from wandering into functions they cannot use, reduces support noise, and keeps the interface truthful. That is a legitimate reason to keep it. It just is not a security control, and the diagram should say so in as many words.

  • The team replies that the API also checks the role, so the client guard is harmless. What should the diagram show?
    Then the enforcing boundary is at the API and that is the only line worth drawing; the client guard is annotated as user experience, non-enforcing. Harmless is not quite right either - a line on a diagram is read as a control, so leaving it unlabelled invites a future reviewer to assume the split is enforced and skip the crossings where it is not.
  • A colleague argues the boundary can sit inside the browser because the bundle is served over TLS with integrity checking.
    TLS protects delivery, not execution. After the response lands, the user can alter runtime state, step past the guard in a debugger, or discard the app and drive the API from a script - none of which touches the transport. A boundary needs an enforcement point on your side of the crossing, and after delivery there is none.
  • What threats does the corrected diagram surface that the original hid?
    Everything an authenticated low-privilege trader can do with a valid token: calling approval endpoints directly, submitting a client-supplied role or limit that the server trusts, and producing audit records that name a supervisor who never acted. While the browser looked like two zones, all of those sat inside a boundary and were never enumerated.

Handing someone a form with half the fields greyed out does not stop them writing their own form. The check that counts is the one done by the clerk who receives it.

saying these in an interview costs you the question

  • Says hiding the button removes the threat
  • Believes minified or obfuscated code makes a client check trustworthy
  • Treats an authenticated user as being inside the trust boundary
  • Claims TLS protects a client-side authorization check
  • Assumes only unauthenticated outsiders are attackers
  • Draws separate zones per UI role inside one browser

context