skip to content

In STRIDE, how do you model Tampering against a process's own configuration and code?

level: middleimportance: should knowfreq 55%

answer

  1. the process reads more than user data
  2. rules and flags are inputs
  3. who may change behaviour, not data
  4. verify on load, then fail closed

basics

~20 s

Treat configuration as an input crossing a trust boundary. Feature flags, rule tables and loaded code decide what a process does, so anyone who can write them changes behaviour without touching any user record — that is Tampering.

solid answer

~50 s

Most people put Tampering rows on flows and stores and stop there, but a process reads more than user data: it reads the rules it obeys. Take a service that fetches feature flags from an unauthenticated in-cluster endpoint — any workload that can reach it can flip a flag and change what the process does, so that flow gets a Tampering row. Same shape on a smart meter that accepts its tariff table as an unsigned blob: whoever holds the device rewrites the billing rates. So I draw config sources as real elements with their own boundaries, then ask three things per source: who can write it, does the process verify it before applying it, and does it fail closed when verification fails. The controls are restricted write, signature-on-load, range validation, and refusing to start rather than defaulting open.

go deeper

for a junior

Remember that configuration, feature flags and rule tables are inputs. If someone can change them, they can change what the program does, and that belongs in the threat list.

for a middle

Be ready to walk a process element and enumerate every source that parameterises its behaviour, then say who can write each one and what the process checks before applying it.

for a senior

Show the failure-mode thinking: what happens on a missing or unverifiable config, why permissive fallbacks turn deletion into forgery, and where verification belongs when the artifact lives on hardware you do not control.

for a principal

Own the platform answer — which classes of configuration require signing at origin versus a narrowed write path, and how you keep that consistent across teams without making every config change a ceremony.

## Why configuration is a first-class Tampering target A process is not just a box that transforms user data. It is a box whose behaviour is *parameterised* by things it reads at start-up or at run time: a config file, environment variables, a feature-flag service, a rules or pricing table, a policy document, a template, a plugin directory, the code artifact itself. Every one of those is an input, and every input has a source, and every source-to-process arrow is a data flow that can cross a trust boundary. The reason this gets missed is that config usually arrives from somewhere that *feels* internal — a shared cluster service, a mounted volume, a local port on the device, a bucket 'we control'. Feeling internal is not a trust boundary argument. The question is always which principals can write it, and whether that set is narrower than the set who should be able to change what the process does. ## Two worked shapes **A feature-flag service read over an unauthenticated in-cluster endpoint.** The flags decide whether a payment path is enabled, whether a new authorization check is enforced, whether a debug behaviour is on. Any workload that can reach the endpoint can flip one. The attacker here is not an anonymous internet user; it is an authenticated, low-privilege workload that got a foothold somewhere in the cluster. The asset is the service's behaviour — the ability to turn a control off from a position that gives no direct access to the data the control protects. The Tampering row goes on the flag flow and, if the flag store accepts unauthenticated writes, on the store too. **A smart meter that accepts its tariff table as an unsigned config blob.** The attacker owns the device; there is no perimeter left to defend. The asset is metering integrity and therefore money. The meter's data handling can be perfect and the meter still bills wrongly, because the *rules* were replaced. Notice that no user data was modified — this is Tampering with the process, not with a store of records. Different attacker positions, different assets, same STRIDE row: an input that determines behaviour, writable by someone who should not determine behaviour. ## How to enumerate it on the diagram When you sweep a process element, do not stop at its request flows. Ask: - **What does this process read that changes what it does?** List config sources explicitly and draw them; a config source that only lives in your head cannot get a threat row. - **Who can write each source?** Name principals, not systems. 'The deploy pipeline' and 'any pod in the namespace' are very different answers. - **Does the process verify anything before applying it?** Verification means an integrity check the process performs, not an assumption about where the value came from. - **What happens when a source is missing, malformed, or fails verification?** A config path that falls back to a permissive default converts a Tampering threat into a trivially reachable one — deleting the file becomes as good as forging it. ## Controls that actually answer it - **Restrict the write.** The narrowest fix and often the right one: config that only the deploy identity may change, a flag service that requires an authenticated caller with an explicit role to mutate, a read-only mount, an immutable image for code. - **Verify on load.** Where the artifact travels through places you do not control — a device in a customer's home, a blob in shared storage — the process should verify a signature over the artifact before applying it, so that possession of the storage is not enough to change behaviour. The verifying key ships with the process; the signing key lives where the tampering party cannot reach it. - **Validate the content.** Integrity checks prove the bytes came from an authorized source; they say nothing about whether the values are sane. Range-check tariffs, bound rule counts, reject unknown fields. This is the layer that catches an authorized-but-wrong change. - **Fail closed.** No verification, no start. A safe default is one that keeps controls enforced, not one that keeps traffic flowing. - **Make changes attributable.** Recording who changed which flag, and when, does not prevent the change, but it converts a silent behaviour swap into something you can find and reverse. ## The interview signal Saying 'and the config is an input too' is a small sentence that separates candidates. It shows you model the system as it actually behaves rather than as the happy-path data diagram suggests, and it usually surfaces the cheapest high-value mitigation in the whole exercise, because config write paths are typically far broader than anyone intended.

  • The team argues the flag endpoint is safe because it sits inside the cluster. How do you answer?
    Inside the cluster is a network location, not a trust level. The relevant question is which principals can reach and write it, and in a shared namespace that set includes every workload that got compromised. I would draw a boundary around the flag service, require an authenticated identity with an explicit write role for mutations, and treat the read path as untrusted input that the consuming service validates before applying.
  • Config verification fails at start-up. Should the process start with the last known-good values?
    Only if last-known-good is stored somewhere the attacker cannot reach and is itself verified — otherwise the fallback becomes the attack. The safer default is to refuse to start and alert, because a process running on stale rules can be as wrong as one running on forged ones. Whichever you choose, make it an explicit design decision recorded next to the threat, not an accident of the code path.
  • A signed tariff table is applied by the meter, but the values are absurd. Which control catches that?
    Content validation, not the signature. A signature answers 'did an authorized party produce this', and it stays silent about whether the authorized party produced something sensible or was itself compromised. Range and sanity checks on the values, plus a plausibility comparison against the previous table, catch the authorized-but-wrong case that every integrity primitive is blind to.

saying these in an interview costs you the question

  • Only puts Tampering rows on user-data flows and stores
  • Calls an in-cluster endpoint trusted because it is internal
  • Assumes a signature also validates the values are sane
  • Falls back to permissive defaults when config is missing
  • Treats deployed config as immutable without checking write access

context