Your pricing engine loads another team's plugin into its own process - where does the trust boundary go, and can one exist inside a process?
answer
- no hop, still a trust change
- who wrote it, what it runs as
- same heap, same identity, same secrets
- a line nothing enforces is a finding
- child process only helps if privilege drops
basics
~20 sTrust changes at the code-ownership seam: foreign code inside your process shares your address space, secrets and privileges. A boundary belongs there, but nothing enforces it in-process - so mark it unenforced, or move the plugin into a separately privileged process.
solid answer
~50 sCode ownership is a trust source in its own right, so the boundary sits where another team's plugin starts executing - with no network hop and no login anywhere near it. What makes this uncomfortable is that in-process nothing enforces it: the plugin runs as the same principal, reads the same heap, sees the pricing model constants and any credentials the process holds, and can crash or hang the engine. Draw the boundary anyway and annotate it as unenforced, because a boundary's first job is to force enumeration; the only control behind it is review and contract. If the assets justify it - trade-secret pricing IP, or availability - the fix is structural: run the foreign code in a child process under a different OS user with reduced privileges and a narrow result channel. A child that inherits the same user changes nothing.
go deeper
Know that code you did not write, running inside your program, has the same access your program does - its memory, its secrets and its permissions - even though nothing crossed a network.
Explain what in-process foreign code actually gets: shared address space, the process identity and its credentials, and the ability to take the process down; and why a plugin interface does not constrain any of that.
Demonstrate the judgment call - draw the boundary and label it unenforced, or restructure so the OS enforces it - and state precisely what makes a child process a real boundary rather than just relocated code.
Own the policy on hosting foreign code: which assets justify the cost of process isolation, what an accepted unenforced boundary must record, and how those acceptances are revisited as the plugin ecosystem grows.
## Trust can change with no network and no login Most people learn boundary placement on diagrams where the boundary happens to coincide with something visible - a client talking to a server, a service talking to a database. The harder and more interesting cases are the ones inside a single machine, where the trust change comes from **who wrote the code** and **what it executes as** rather than from where the packets go. Take a pricing engine in a monorepo that loads another team's plugin into its own process at startup: a pluggable strategy that computes an adjustment. There is no hop, no authentication event, no tenant switch. Yet the trust level plainly changes at the call into that plugin: you did not write it, you do not review every change to it, and its authors' compromise - a bad merge, a compromised developer account, an upstream dependency pulled into their module - becomes your compromise. ## What is actually at stake Name the adversary and asset before arguing about the line. Here the adversary is a compromised upstream team or a dependency inside their module, and the assets are the trade-secret pricing model and the engine's continued operation. In-process, foreign code gets: - **The whole address space** - your model coefficients, cached inputs, and anything else in memory, which is IP disclosure without a single outbound flow appearing on your diagram. - **Your process identity and credentials** - every secret the engine holds, every downstream system it may call, and its ability to write wherever it may write. - **Availability** - an uncaught exception, an infinite loop, an allocation storm, or a call to exit takes the engine down with it. So the crossing is real, and if you did not draw it none of those threats appear in the enumeration. ## The awkward truth: a boundary you cannot enforce A trust boundary is a *claim about trust*, but a boundary is only a *control* when something at the crossing enforces it. Inside one process nothing does - same address space, same principal, same rights. A language-level module system, a plugin interface, or an internal API surface is an engineering convention, not a security control against code running beside it. That leaves you two honest options, and the senior answer is knowing which you are choosing: 1. **Draw the boundary and label it unenforced.** The line still earns its place: it forces the threats above onto the list and makes the assumption explicit - "we accept the plugin's authors as fully privileged inside this process, controls are code review and the ownership contract". Now it is a stated risk somebody can accept or reject, not an invisible one. 2. **Change the design so the line can be enforced.** Move the foreign code out of the process. ## When the process change *is* the boundary Option two is the reason execution context appears in the list of trust-change triggers. Consider a different shape: a media-transcoding worker that shells out to a third-party codec binary as a child process to handle uploaded files. The adversary is a compromised dependency arriving as a malicious input file, and the asset is availability of the transcode fleet. Here the process split does the work: - The child has its own address space, so a memory-corruption bug in the codec does not immediately hand over the worker's credentials. - The child can run as a **different OS user** with no access to the worker's secrets, a read-only view of the input, a scratch directory for output, and no network. - It can be capped - CPU time, memory, wall-clock - so a decompression bomb costs one job rather than the fleet. - The result channel is narrow and typed: a file plus an exit status, both validated by the parent before use. That is an enforced boundary, and it is enforced by the operating system rather than by discipline. The caveat matters as much as the pattern: **a child process is not automatically a sandbox**. Fork a child as the same user, with the same environment, the same file descriptors and the same network access, and you have moved code without moving privilege. The boundary exists when the privilege on the far side is genuinely smaller and the inputs and outputs crossing it are constrained. ## How to reason about it in an interview Work the derivation out loud in this order: *what changes here* (code ownership, then execution context), *what does the far side get* (memory, identity, availability), *what enforces the line* (nothing in-process; the OS once split), *what do I write on the diagram* (boundary with an unenforced annotation, or a real one after the design change). A candidate who states that a boundary with no enforcement is a finding rather than a control - and who does not pretend a module interface is a security perimeter - is demonstrating exactly the judgment the question is asked for.
- Does moving the foreign code into a child process automatically create a trust boundary?No. A child that inherits the same OS user, environment, file descriptors and network access has the same privileges as its parent, so nothing about trust changed - you only moved the code. The boundary exists when the far side runs as a different principal with reduced rights, constrained inputs and a narrow, validated result channel.
- What do you write on the diagram when a boundary you believe in cannot be enforced?Draw it, mark it explicitly as unenforced, and name what stands in for enforcement - code review, an ownership contract, provenance of the artifact. The value is that the crossing still gets enumerated and the acceptance becomes a recorded decision instead of an assumption nobody knew they were making.
- How does this change for a third-party library compiled in at build time rather than loaded at runtime?The trust change is identical - foreign code executing as you - but it lands earlier, so the crossing to model is the ingestion of the artifact rather than a call at runtime. In-process you again have no enforcement, and the controls belong to how artifacts enter the build, which is supply-chain work rather than something this diagram can fix.
Lending someone a desk in your office is not the same as giving them a visitor badge and a meeting room. Inside the room they see only what you brought; at your desk they see everything.
saying these in an interview costs you the question
- Says same process means same trust, so no boundary exists
- Treats internal or first-party code as automatically trusted
- Assumes any child process is a sandbox
- Thinks no network hop means nothing to model
- Calls a plugin interface or module system a security control
- Claims code review turns an unenforced boundary into an enforced one