turingtower/blog

Instrumentation Inherits Its Author's Blindspots

The assumptions an attacker violates are not always visible from inside the head that made them, so self-instrumented systems are blind in a direction you can predict from who wrote the logging. You cannot log the violation of an assumption you did not know you were making.

Instrumentation records what its author was thinking about, for example a developer logs to answer “did this work?”, and the telemetry captures outcomes such as request succeeded, record written, etc. Important questions for keeping a system running but not always ideal for noticing that someone is using the system in a way it was never built to be used, which is quite close to attacker behaviour as their whole job is to operate outside the author’s model of how the system gets used.

So the same event can encode multiple readings, while standard telemetry keeps one. Consider these examples.

  • A state transition with no preceding fetch. A frontend produces requests in an order the UI can generate: load a resource, then act on it. Suppose a request arrives that mutates state the client never read first: customer_1.firstname updated but the caller never read the record in a reasonable operational window. Here every endpoint returns 200 and the calls are individually valid, however this is an ordering the frontend cannot produce, ergo the requests did not come from the frontend ergo something is driving the API directly. This may not necessarily be a threat actor but it is highly unlikely to be a regular user.
  • A correct credential in a context that never legitimately produces it. Authentication logging typically records boolean outcomes, however the right token in the wrong choreography is a success. Suppose user_2’s token authenticates directly against the reporting service, but user_2’s role only ever reaches reporting as a downstream hop from the dashboard session and never as a first-party authentication. Direct authentication to that service is a sequence the application’s own flow does not produce, and it is conceivable the token is being presented by something that did not walk through the app to get there. Again not necessarily a stolen credential, but it is unlikely to be the real user using the standard client. Telemetry built to answer “was this login valid?” doesn’t capture this.
  • A capability exercised outside the declared workflow. A public profile page lets users update their username and phone number, while the same endpoint is also used internally to change an account’s lifecycle status. Telemetry shows the public client successfully changing that status, even though the legitimate frontend never sends the field. This could reflect an undocumented integration, parameter tampering, or weak field-level authorization. Operationally, the update succeeded; from a security perspective, the client exercised a capability outside the declared workflow.

In each case the readings are correct and did contain the information deemed relevant by the author, but they are blind to important nuance as a consequence of their authorship.

Improve your approach to logging

Behavioral baselining and anomaly detection have worked this ground for a long time, and what these techniques import is a threat model the original author did not have. Nobody stumbles into the attacker’s reading of their own events and it has to be brought from outside the head that built the system.

Most instrumentation logs the expected behaviour of operations, even a try catch is ultimately an anticipated negative outcome. The attacker-relevant signal is in the violation of these assumptions. To get the second reading, start with the following:

  • Log the application’s assumptions. A practical way to do this is to generate logs that reconstruct the architecture and process flow. For example: this endpoint is only called after that one; this identity does not authenticate from that context; this field is not in the live UI; this request takes at least this long, then log every time one of them is false. This significantly improves your ability to detect anomalies as you spot behavioural drift or even just identify new ways to optimize the codebase.
  • Work with the security team and log the threat model. Much like UAT, security professionals such as pentesters don’t see your application the way you see it, as such they will not use it the way you expect. Work with them to model offensive usage patterns and instrument logs for those journeys. You get the ability to detect nefarious behavior quicker and can reconstruct incidents faster.

Treat these assumptions like feature tests for production behaviour. A feature test states that, given a particular user and application state, a specific sequence of actions should be possible. Security instrumentation can express the inverse: if production generates a sequence outside the application’s declared and observed legitimate workflows, record the violated assumption. The rule should be concrete enough to test, such as: an update by this client must be preceded by a read of the same resource within the same session, except through these named administrative or batch workflows.

Like tests, these rules need fixtures, ownership, and maintenance. Run them against recorded legitimate traffic to establish appropriate correlation windows and identify missing workflows before enabling alerts. When the application changes, the corresponding assumption should change in the same pull request. A rule that repeatedly flags legitimate activity is the equivalent of a failing test caused by an outdated specification: fix or remove it rather than teaching operators to ignore it.