Map the System Before You Hunt
In Cloudflare's security-audit skill, reconnaissance is the work of discovering which boundaries a review can meaningfully test. This chapter focuses on the system map behind a security claim—who acts, where input enters, what state or copies it touches, which control owns the decision, and which facts belong to the deployment rather than the source—so readers can turn architecture into a defensible starting scope.
A repository rarely presents itself in the same shape as an attack. It may contain routes, workers, queues, storage clients, build jobs, browser code, and configuration overlays. A security question cuts across those pieces. An ordinary account enters through one interface, a value is normalized, a service identity performs a lookup, a cache stores a result, and a later request reads it under a different context. If the reviewer studies each component in isolation, the boundary can disappear between interfaces.
Reconnaissance prevents that disappearance. It is not a tour of every file. It is a reconstruction of authority and consequence.
Four views of one system
The skill divides reconnaissance into four complementary views. Each view answers a different question, and the map becomes useful only when the answers connect.
Product, stack, and local operation
First identify what the product does in terms of trust-sensitive actions. Who uses it? Who operates it? What can a normal user create, change, invoke, export, or retain? Which resources matter: another user's data, a shared queue, a release artifact, a workload identity, a privileged process, or an operator-owned budget?
This product view prevents a technical inventory from becoming an architecture model. A service is not security-sensitive merely because it contains an API. Its importance comes from what that API lets a principal do. A coding-agent service, for example, may appear to be a text-processing application until the map shows that model output can select a tool, a tool can use a service credential, and the result can alter a protected resource. The trust-sensitive action is the link among those components.
The stack and local-operation view then asks how the product actually runs in the evidence available to the reviewer. Languages, frameworks, build systems, runtimes, test harnesses, and locally visible deployment models matter because they determine which paths can be read or exercised safely. A local fixture may establish a parser result. A rendered policy may show which identity a configuration grants. A hosted identity provider, proxy, browser policy, or cloud attachment may remain outside the repository.
That distinction is important even before testing begins. The workflow asks for exact offline build and test commands, expected write locations, and the target-controlled inputs they process, but it does not run them during reconnaissance. It also asks which commands would fetch dependencies, publish artifacts, contact provider APIs, or affect shared state, so those activities can be excluded rather than discovered accidentally during an audit.
Principals, authority, and controls
The second view maps identity and authority. A principal is an actor or process whose permissions matter in the system: an unauthenticated caller, an account, a tenant, a browser origin, a contributor event, a workload, a plugin, a model or tool peer, another local application, or an operating-system user. The same person may appear as different principals at different boundaries. A web request can become a service account call; a browser message can reach a native helper; a queue message can be processed under a worker identity.
For each principal, ask what they may do by design and how that authority changes. Authentication identifies a caller, but authorization decides which resource and operation they may use. A channel may be authenticated while a request field still selects another tenant. A service may possess a broad credential while a handler narrows each query to the requesting user. A model may generate a tool call while a deterministic handler still has to authorize the final resource.
The map should therefore attach each control to the decision it owns. An ownership predicate protects an object relationship. A signature check establishes message authenticity, but may not establish the sender's authority over a particular resource. An origin allowlist controls a browser boundary. A quota controls shared cost only if it is applied to the principal and resource whose budget matters. A confirmation step controls intent only if it binds the exact normalized action, not merely a human-readable description.
This way of mapping controls also exposes alternate paths. If a direct request, batch operation, retry, background job, and administrative route all produce the same state change, the relevant question is whether they enforce equivalent policy. The most polished route is not the effective policy if a sibling route accepts a weaker identity or omits the resource check.
Entry surfaces, copies, and sinks
The third view starts with input rather than components. Inventory where lower-trust material enters: HTTP and browser requests, protocol messages, files and archives, command-line or environment values, plugins and dependencies, CI events, cloud events, model context, tool arguments, mobile links, and local IPC. The list matters only as a starting point. The essential work is following each important input through its transformations.
Parsing can change meaning. Normalization can change which resource a value names. Authorization can bind one identity while a later lookup trusts a body field. Storage can make content safe for one context and dangerous in another. A field that is harmless when stored may become a URL, a file path, a policy expression, a search key, or a tool argument later. The map should record those transitions without assuming that validation performed at one stage survives every later representation.
Copies deserve equal attention. A primary record may have a cache entry, search document, embedding, preview, export, backup, queue message, trace, or analytics record. Each copy can have different access rules and a different lifecycle. A role downgrade or deletion in primary storage does not by itself prove that a cached response, queued job, or restored snapshot has lost the old authority. The question is who writes the copy, who reads it, which identity is present, and what event invalidates it.
A sink is the point where the input produces a security-relevant effect. It may be a database mutation, an HTML render, a shell or file operation, a message publication, a cloud API call, a privileged helper method, a release promotion, or a resource-consuming loop. The sink is not automatically dangerous. It becomes relevant when the path reaches it with the wrong principal, resource, representation, lifecycle state, or budget.
Local execution and deployment visibility
The fourth view determines what can be established without guessing. The skill asks which small offline tests or fixtures can validate a boundary with dummy data, whether isolated loopback processes are possible, and which environment controls are missing. It also identifies deployment facts that source cannot establish: proxy behavior, provider policy, browser headers, cloud network attachment, broker ACLs, OS permissions, signing, packaging, hosted identity, retention, and runtime drift.
This is not a retreat from source analysis. It is a way to state its reach precisely. Source may show that a backend consumes a forwarded identity header. It may not show whether a trusted ingress removes client-provided copies. Source may define a public service route, but an external network policy may decide whether that route is reachable. A manifest may request a permission, while the final merged package or device policy determines whether the component is exported. The map must show both the source-visible path and the external fact that could change its meaning.
An active deployment path also has to be distinguished from a declared possibility. Defaults, environment values, command-line flags, per-region overlays, sidecar injection, feature gates, and compatibility routes can change which control is actually attached. The skill therefore asks reconnaissance to identify the final active source path for each deployment mode only where the repository selects it deterministically. If the source contains several plausible configurations but cannot establish which one runs, that ambiguity belongs in the scope and later validation plan. It should not be resolved by choosing the most convenient manifest.
A practical map can be read as a boundary matrix. For each active path, record the lower-trust entry, the authenticated identity, the network or process peer, the state and secrets it can reach, the resource it can select, and the control that should constrain it. The purpose is not to create another inventory. It is to expose mismatches: a route has tenant authorization but its background copy does not; a workload has a narrow application role but a fallback credential is broader; a browser cache survives account switch; a release step tests one artifact and promotes another. Each mismatch points to a question that a coverage unit can later own.
The four views meet in a simple relationship:
The solid path is what reconnaissance can often trace in source. The dashed path represents facts that may decide reachability, identity, or containment but live outside the repository. The distinction is not cosmetic. It determines whether a later lead can be confirmed locally or must remain a source-grounded needs_validation record.
From architecture to review scope
A useful system map does not merely describe the target; it decides where depth is justified. The skill's domain companions are selected because reconnaissance finds the corresponding boundary. A browser message, for example, calls for origin and storage reasoning. A queue or RPC route calls for peer identity, routing, replay, and delivery semantics. A workload manifest calls for active configuration and cloud identity. A native parser calls for memory, lifetime, ABI, or privileged-interface analysis. The presence of a language or dependency name alone is not enough.
This selective approach solves two opposite problems. If every possible attack class is loaded for every target, agents receive a catalogue rather than a scope. They may produce generic concerns detached from the product's actual authority. If only the most familiar class is selected, important boundaries disappear: a web review may ignore caches and browser state; an API review may ignore export and retry paths; a cloud review may ignore the application-level identity that a manifest does not enforce.
Reconnaissance should also preserve negative decisions. If a domain is considered and excluded, the reason should be visible in the scope rather than inferred later. “No browser boundary exists” is different from “browser review was forgotten.” “The repository does not select a deployment mode deterministically” is different from “the deployment is safe.” The first is a bounded exclusion; the second is an unsupported conclusion.
The architecture summary is deliberately compact, but the detailed assignment belongs with the eventual coverage unit. That separation keeps the summary readable while retaining the exact relationship among surface, boundary, subsystem, attack class, starting paths, selected companions, and excluded blocks. A reader should be able to see why a unit exists without mistaking the assignment label for evidence that the unit was completed.
This map is also where lifecycle enters the design. A security boundary is often temporal. A token is issued, used, refreshed, revoked, and possibly replayed. A record is created, copied, deleted, restored, or migrated. A request is accepted, queued, retried, acknowledged, or canceled. A role changes while a session, cache, subscription, or background job remains alive. Reconnaissance must mark the transitions that can change authority, state, or resource use, not just the initial and final endpoints.
A good lifecycle map names the owner of each transition. Who can create the state? Which identity is rechecked when it is resumed? Does cancellation stop the downstream work or only return a response to the caller? Does deletion propagate to queued processors and derived copies? Does restoration apply current authorization, or does it revive an old permission along with old data? These questions connect an apparently ordinary operation to the point where its security meaning changes. They also prevent a reviewer from treating a successful initial check as protection for every later stage.
The result is a more demanding but more useful starting question. Instead of asking, “Which files should the agent inspect?” ask, “Which lower-trust principal can reach which decision, through which interface and representation, under which lifecycle and deployment conditions, and what protected resource would be affected?” The answer identifies the surface to review, the control to compare, the domain guidance to select, and the evidence that would settle the claim.
That is why the next stage can make coverage inspectable. Once the system map identifies material combinations of surface, boundary, subsystem, attack class, and lifecycle, those combinations can become stable units with explicit owners, evidence, and unresolved facts. Without the map, a coverage ledger would only count activity. With it, the ledger can describe what the review actually set out to establish.