Guide 012 worked guide

How to check whether a flagged code path can actually be reached

Check whether a flagged code path is actually reachable by the proposed actor in the relevant build, route, and deployment context.

To check a flagged path, identify the exact entry that could call it, establish that the entry is in the deployed application, follow the branch and input conditions to the suspicious operation, and record the controls and privileges an actor would need. A search hit for a function proves that the function exists; a call graph edge suggests a possible call. Neither by itself proves that a production user can exercise the path. If deployment configuration, dynamic dispatch, or an alternate caller is unknown, record reachability as unresolved instead of dismissing the alert.

CodeQL describes a data-flow path as a way to explain how a value can move through a program, and its path queries expose those explanations in alerts. A reviewer still has to check whether the modeled path matches the code and the environment being assessed. OWASP's code review guidance calls for examining data flow and application logic alongside automated results.

Reachable has four different meanings

Ask which of these you have established:

Layer Question Useful evidence
Included Is the flagged code in the exact build or artifact under review? Artifact digest, build manifest, source map, package contents.
Invoked Is an active route, job, event handler, or caller able to enter it? Route registration, queue subscription, scheduler config, call sites.
Accessible Can the actor in the claim satisfy the required login, role, network, flag, and object conditions? Policy code, gateway config, flag state, permission mapping.
Harmful flow Can the actor-controlled value reach the operation in the form the alert assumes, and can the stated effect occur? Input transformations, branch predicates, sink behavior, relevant controls.

A function can be invoked by a trusted batch job yet inaccessible to a public user. A route can be public but never pass the attacker-controlled value to the flagged operation. A source-supported harmful flow can exist in staging but not in the production artifact. These are different verdicts, and they need different evidence.

Illustrative case: the legacy import parser

Illustrative repository: Cedar Records. An analyzer highlights a call to a legacy archive deserializer and says a remote user can make the API process an untrusted archive. At revision c42, the source resembles this simplified pseudocode:

if settings.legacy_import_enabled:
    POST /admin/import -> require_staff -> parse_legacy_archive(request.body)

worker.on("archive-replay", message -> parse_legacy_archive(message.archive))

The highlighted parser exists. The web route appears to require staff access and a feature flag. A worker also calls the parser with queue data. The scanner's public-user claim may be wrong, but saying “the route is disabled” is not enough to dismiss every path. The security engineer needs the production flag value, route registration semantics, worker deployment and queue write authority, and the parser's actual behavior. The snippet alone does not establish an exploit.

A first pass through the evidence might produce this path ledger:

Candidate entry Present in production? Actor and gate Input to parser Current conclusion
POST /admin/import Deployment owner says flag is off; no signed config record yet Staff role if registered Request body Web reachability unresolved pending effective flag proof.
archive-replay worker Worker image includes handler Queue publisher list not yet inspected Message.archive Separate reachable-call question; trust boundary unknown.
Local migration script File is in repository; artifact excludes it Operator on a workstation Local file Not evidence for a remote API claim.

The important output is the next fact to collect, not a premature severity score. The deployment owner can supply the effective production flag and artifact ID. The platform owner can supply who can publish to the queue. The reviewer can then revisit the precise claim at the same revision and deployment.

Complete the missing edges

Continue Cedar's constructed exercise with an effective configuration record tied to image D: legacy_import_enabled=false, evaluated when that web router is registered. The route registry for D contains no /admin/import. This defeats the web-entry premise for this image and configuration. The repository default alone would not have done so.

Next, the queue policy names one publisher, import-service. That sounds reassuring, but inspect what it publishes:

customer upload
  -> authenticated import-service
  -> verifies upload belongs to this customer
  -> stores original archive as object U17
  -> publishes {kind: "archive-replay", object: U17}
  -> worker reads U17 and calls parse_legacy_archive(bytes)

The service owns the queue credential. The customer still controls the archive bytes. A check that the upload belongs to the customer prevents reading someone else's upload; it does not transform that upload into trusted parser input. The supplied worker source performs no format conversion before the legacy parser. Its deployment registration subscribes to this message kind.

Completed reachability conclusion: the public web route is absent, while a signed-in customer can supply bytes that the worker passes to the flagged parser through the import service. This establishes the input-to-operation path, not the deserializer's alleged harmful behavior. The next review must check the specific parser preconditions and effect. Do not keep asking for queue write permissions once the actual producer and input provenance are established.

Recover a handler that a caller search misses

A search for parse_legacy_archive( may find the worker body but no registration because a plugin registry loads it by name. For this exercise, the selected build includes:

worker registry W4:
  archive-replay -> legacy_import.handle

legacy_import.handle(message):
  bytes = object_store.read(message.object)
  parse_legacy_archive(bytes)

The registry supplies the missing invocation edge. To rely on it, bind W4 to image D and inspect the loader's selection of legacy_import.handle. A file named registry.example would not suffice. Conversely, if the effective registry omits the handler and no other dispatcher invokes it, that is meaningful counterevidence for this entry.

The working output now has two independently scoped lines:

Entry Final reachability result Remaining work
Web import Not registered under D's effective flag. Reopen if flag or registration changes.
Queue replay Customer-controlled archive reaches legacy parser through the sole authorized publisher. Review parser-specific harmful behavior and constraints; corroborate the claimed effect before confirming the vulnerability.

This is the distinction the four-layer model is meant to preserve: included, invoked and actor-controlled does not automatically mean the claimed harm is established. No archive or customer code was executed in this exercise.

What counts as counterevidence?

A call graph with no path is useful as a search aid but is not enough if the framework can register handlers dynamically. A single quiet traffic period is also weak: an endpoint may be rarely used. A code comment saying “staff only” is a claim to verify, not a control. Stronger counterevidence ties a specific build and environment to a disabled route or shows a compulsory, effective gate on every relevant caller.

For Cedar Records, a signed deployment snapshot showing the legacy web route disabled would defeat the web-entry premise for that release. It would not answer whether an internal publisher can place attacker-influenced archives on the queue. A queue policy showing only a trusted service principal can publish narrows the actor, but the reviewer must still ask whether that service accepts untrusted input. “Internal” is a location, not a trust proof.

If the route was enabled last month and disabled now, record the period separately. If a fix removes a call, verify the new artifact and all relevant callers. A missing search result or deleted file does not by itself prove the dangerous behavior cannot recur through another path.

Use branch conditions as evidence, not decorations

The Cedar path contains more than a sequence of function names. Each arrow has a condition: the message kind must match, the worker must load the selected object, and the parser call must occur on the branch taken by those bytes. A reviewer should record these conditions beside the path so that a later person can challenge them without reconstructing the entire service.

For example, consider an alternative worker that rejects every customer upload before the legacy call and reserves that call for server-generated migration objects. The parser would still be included and invoked, but the proposed customer-controlled path would fail at the object-selection branch. To accept this counterevidence, trace how the worker distinguishes those objects. A client-provided trusted=true field is not equivalent to a server-controlled classification.

A useful branch worksheet for the original exercise is:

Decision Input to inspect Evidence needed
Dispatch archive replay Effective message kind and registry The selected worker maps the message to this handler.
Load the archive Object reference constructed by the producer The retrieved bytes are the customer's original upload.
Invoke legacy parser Worker branch and any conversion No earlier decision replaces or rejects the customer bytes on this path.
Interpret the result Parser behavior and subsequent use Separate evidence establishes the alleged harmful effect.

The last row remains deliberately unresolved. Reachability work should not inherit the scanner's strongest impact claim merely because the first three rows are complete. A parser may be reachable while the advisory's required option is disabled, or while its proposed effect concerns a different operation. That is the next analysis, with its own evidence.

Keep a search boundary visible

Searches are often the fastest way to find callers, but record their limits. A source search may omit generated code, configuration held outside the repository or another service that publishes the same message. “No additional caller found in the selected source directories” is accurate; “no additional caller exists” requires a stronger inventory. When dynamic registration is involved, the effective registry and its loader are often more useful than repeating a textual search.

Bound the follow-up to the missing mechanism. For Cedar, ask platform for the subscriptions and publisher bindings of the archive-replay queue used by image D. Do not ask for every queue in the company. If another producer appears, inspect whether it can carry attacker-controlled bytes; its mere presence does not automatically expand the original actor set.

At handoff, name the layer you have established: “customer input reaches the parser” is a completed result even when parser exploitability remains open. This keeps an investigation moving and prevents later reviewers from spending their time re-proving the already documented route.

A handoff that moves the review forward

Use a short handoff with five fields: claim at revision and artifact; path established; path disputed; missing evidence and owner; provisional decision. For the example:

At c42/image D, the web route is absent under the effective flag. The deployed queue worker receives customer-controlled archive bytes through the authorized import-service publisher. Queue restrictions do not defeat that input path. AppSec owns the remaining parser-behavior review; platform supplies any missing runtime constraints. The outcome is a supported reachability chain, not an executed exploit or approved vulnerability.

This is more useful than “unreachable” or “needs repro.” The next reviewer knows what observation would change the result. To understand how the overall false-positive decision should be recorded, use the false-positive investigation guide. If the disputed gate is shared middleware, continue with the middleware authorization walkthrough.