skip to content

When threat-modeling a web app, why is the browser drawn as an external entity outside your trust boundary?

level: juniorimportance: must knowfreq 78%

answer

  1. you do not run this element
  2. it lives on the user's machine
  3. everything inbound is authored
  4. client checks are UX, not controls
  5. external entity: spoofing and repudiation

basics

~20 s

The browser runs on the user's machine, so every field, header and request sequence it sends is attacker-authorable. Draw it outside your trust boundary: it is an input source, never a place where a rule is enforced.

solid answer

~50 s

On a data-flow diagram the browser is an external entity: something you interact with but do not run. The trust boundary sits at your server's request-handling edge, and everything crossing it inbound is authored by whoever controls the client - visible fields, hidden ones, headers, the order requests arrive in, and whether a human was involved at all. That makes client-side validation, disabled buttons and a hidden amount field usability features rather than controls; a model that credits them has invented a mitigation that does not exist. On a municipal parking-fine site with an anonymous 'pay without an account' flow, the posted fee is a claim, so the handler recomputes it from the fine record and ignores what arrived. In STRIDE-per-element terms the external entity attracts spoofing and repudiation, while the flow crossing the boundary attracts tampering and information disclosure.

go deeper

for a junior

Be ready to say in one sentence that the browser sits outside the boundary because you do not run it, and to give one concrete check that must therefore be repeated on the server.

for a middle

Explain what the placement implies mechanically: which flows carry attacker-authored data, why each handler re-derives its own facts, and which STRIDE categories attach to an external entity versus the flow crossing the line.

for a senior

Show that you can spot invented mitigations in someone else's model - a threat rated low because the UI prevents it - and describe how you verify that a claimed control actually executes server-side.

for a principal

Own the standard your teams model to, so a portfolio of diagrams does not accumulate risk ratings that rest on behaviour a user can edit. Decide how client-side behaviour is recorded and reviewed.

## What a trust boundary is actually grouping A data-flow diagram used for threat modeling is not a deployment picture. It groups elements by **who runs them and under whose authority they execute**. A trust boundary is the line where that answer changes, and its whole purpose is to mark the crossings where data or a request moves from one level of trust to another - because those crossings are where you have to do work. A browser is the cleanest example available. You wrote the page it loaded; you do not run the thing that executes it. It sits on a laptop you have never seen, under an operating system you do not patch, next to extensions you did not install, and its developer tools are one keypress away. That is the entire argument: **placement follows control, not code authorship**. The JavaScript is yours, the execution is not. ## What follows mechanically Once the browser is outside, everything on the inbound flow is a *claim*, not a fact: - Form fields, including hidden ones and ones a `disabled` attribute greyed out. - Headers, and any value a page put in one. - Which endpoint is called, in which order, and how fast. - Whether the request came from your page at all - the same HTTP request can be produced by a script that never rendered your UI. So the model must treat every inbound flow as untrusted input and ask, per crossing: what is validated here, and where is the authority for this decision. On a parking-fine site, the anonymous payment flow posts a fine reference and an amount. The amount is not data the server may use; it is a suggestion. The server looks up the fine and computes the fee itself. If the model records 'the page only offers the correct amount' as the mitigation, the threat is live and the risk rating is a fiction. The asset here is money, and the attacker is an anonymous member of the public - no account, no privileges, nothing to compromise first. ## The invented-mitigation failure The most common defect in a first web-app model is not a missed threat; it is a **credited control that runs on the attacker's side of the line**. It looks like this: | Claimed mitigation | Where it runs | What it is worth | | --- | --- | --- | | Client-side field validation | Browser | Usability. Zero. | | Disabled or hidden submit button | Browser | Usability. Zero. | | Hidden form field carrying a price or role | Browser | Worse than zero - it advertises the parameter. | | A multi-step wizard that enforces order | Browser | Zero; steps can be called directly. | | Server recomputes the value from its own records | Server | The actual control. | Keep the client-side checks - they give instant feedback and cut junk traffic - but record them in the model as user experience. The defect is not having them; it is listing one as the answer to a tampering threat and then rating that threat down. ## TLS does not move the line A second recurring mistake is treating HTTPS as though it made the browser trusted. Transport security protects a flow **in transit** against a third party: it gives confidentiality and integrity between the two endpoints, plus server authentication. It says nothing about whether the endpoint at the other end is honest, and it certainly does not stop the person operating that endpoint from editing what they send. An attacker's own requests are encrypted too. On the diagram, TLS annotates the flow; it does not move the boundary. ## Which threat categories attach here In STRIDE-per-element analysis, element type determines which of the six categories are worth enumerating: - **External entity** (the browser, the user behind it): **spoofing** - is this identity what it claims to be - and **repudiation** - can this party later deny having acted. - **Data flow** (the request and response crossing the boundary): **tampering**, **information disclosure**, **denial of service**. - **Process** (your request handler): all six. - **Data store**: tampering, information disclosure, denial of service, plus repudiation where the store is the log that has to prove what happened. Each category names a violated property: spoofing violates authentication, tampering violates integrity, repudiation violates non-repudiation, information disclosure violates confidentiality, denial of service violates availability, elevation of privilege violates authorization. Naming the property is what turns a category into a testable requirement. ## How to draw it Put the browser at the left as an external entity, draw one boundary around what you run - the handler process and its stores - and let every request and response cross that single line. Resist drawing the boundary around 'the internet': a boundary that separates nothing you can act on tells you nothing. The value of the line is that it forces the next question for each crossing, which is what the rest of the model is built on: what does this handler verify about this request before it acts on it, and does that verification live on my side of the line.

  • A native mobile client and a script hit the same endpoints. Does the diagram change?
    Not in substance. They are the same class of element: things you do not run, sending requests you must treat as authored. Add them as separate entities if their identity or authentication differs, but the boundary and the server-side checks are identical. Anything that would only hold for a well-behaved browser was never a control in the first place.
  • If client-side validation is not a security control, why keep it?
    Because it is a usability and cost feature: instant feedback, fewer round trips, less junk load. Keep it and record it in the model as user experience. The defect is listing it as the mitigation for a tampering threat and rating the risk down on that basis, which leaves a live threat looking handled.
  • Where exactly does the trust boundary line go for a server-rendered app?
    Around the code you run - the request handler, its process, its data stores - so that every inbound request and every response crosses it. Drawing it around 'the internet' makes it useless, because it stops telling you which specific flows need validation and authorization at the moment they arrive.

The browser is the form you hand a customer at a service window. You can print the boxes, but you cannot stop them writing whatever they like inside. The clerk on your side of the glass still checks every field before acting.

saying these in an interview costs you the question

  • Says TLS makes data arriving from the browser trustworthy
  • Counts client-side validation as a mitigation and rates the risk down
  • Assumes requests arrive in the order the UI allows
  • Draws the browser as a process inside the trust boundary
  • Thinks hidden fields and disabled buttons hide values from the user

context