A flaw needs local execution on a CI runner. What does a fork pull-request build do to that precondition?
answer
- the runner's job is running untrusted code
- who can open a pull request?
- does the build hold project credentials?
- ephemeral host or reused across jobs
- same words, different stage per host class
basics
~20 sIt hands the precondition away for free. Running contributor-authored build content is the runner's job, so anyone who can open a pull request already has local execution, and the flaw moves from post-compromise to initial access.
solid answer
~50 s"Requires local execution" normally means an attacker must already be on the host, which places the flaw after initial access. A build runner inverts that, because executing untrusted, externally authored code is the service it exists to provide. A pull request from a fork supplies build scripts, test code and dependency manifests, and a trigger that runs them in the base project's context with the project's credentials available gives that code the exact position the advisory called a precondition. So the same flaw is a post-compromise privilege problem on a laptop fleet and an internet-facing initial-access problem on the runner. Two facts decide which you have: whether any trigger runs branch-authored content with the project's own credentials, and whether the runner is ephemeral or a long-lived host reused across jobs, so the position persists past the build that obtained it.
go deeper
Know that a build runner executes code supplied by the change under test, so 'needs local execution' is not automatically a hard requirement there.
Explain the inversion and the two facts that size it: whether the build runs with the project's own credentials available, and whether the runner is reused across jobs.
Demonstrate that you re-read every 'local' finding by host class, and that you treat who can trigger a build as an access-control decision rather than a workflow detail.
Frame build infrastructure as a host class whose defining property is executing untrusted content, and be ready to argue what that should change about how the estate provisions credentials to it.
## The wording and the naive reading An advisory that says "local access required" or "the attacker must be able to execute code on the affected host" reads, on first pass, as reassuring. Local execution sounds like the end of an intrusion rather than the beginning: someone already broke in, so this flaw is a second-order concern about how much worse things get. That reading is a claim about your estate, not about the flaw, and on build infrastructure it is usually false. ## Why a build runner inverts it A continuous integration runner exists to check out a revision and execute whatever that revision says to execute. The build definition, the test suite, the code generators, the dependency manifest and the scripts they invoke are all content, and on a public project or a large internal one, that content is authored by whoever opened the change. So the sentence "the attacker must be able to execute code on the host" describes the runner's normal, documented, intended behaviour. There is no compromise step to earn the position. The position is the product. The consequence for classification is direct: the flaw's stage is not post-compromise on this host class. It is initial access, and the actor set is "anyone who can open a pull request", which on a public repository means anyone at all. ## The two facts that decide it Not every pull-request build hands the position away with the same value attached. Two properties matter, and both are checkable in an afternoon: **1. Whose context does the build run in?** A build that runs the fork's content in an isolated context, with no access to the project's own credentials, caches or artefact-publishing rights, still gives the contributor code execution but on a throwaway footing. A trigger designed so the build can reach project secrets, so that pull requests can be tested against real integrations or can publish preview artefacts, runs the same untrusted content with the project's identity available to it. That second shape is the one that converts a build convenience into an externally reachable position of real value. **2. Is the runner ephemeral?** A runner created for one job and destroyed afterwards limits the position to the life of the build. A long-lived host that serves job after job keeps state between them: tool caches, dependency caches, credential material left in the agent account's home directory, and any live sessions the previous job established. On a persistent runner, code obtained through one pull request sits on the same host as the next team's build, and the position it holds outlives the change that granted it. ## Adjacency is the same move on a different surface "Requires network adjacency" behaves identically. Adjacency is defined by the advisory but satisfied by your topology. If the build network shares a VLAN with the laptop fleet, then every laptop, and therefore every phishing victim and every visiting contractor's machine, is adjacent to the build hosts, and an "adjacent network only" flaw on the build hosts is reachable from the least trusted device population in the company. The advisory did not change. The floor plan did. Both cases teach the same discipline: the precondition names a position, and whether that position is scarce is a fact about your estate that only you can supply. ## What this changes about how you read the record Three practical shifts follow: - **Read host class before you read the precondition.** The same three words mean different stages on a laptop, a database server and a build runner. Classifying a flaw without naming the host class it is deployed on is classifying the advisory rather than the risk. - **Treat "who can trigger a build" as an access-control question.** It is the enrolment mechanism for the position the advisory is talking about. On a public project, that enrolment is open to the world. - **Expect the inversion elsewhere too.** Any host whose job is running content it did not author has the same property: a shared multi-tenant execution service, a scriptable reporting engine, a plugin host, a sandbox someone chose to run on a production network. Build infrastructure is simply the most common example and the one with the most valuable credentials sitting beside it. ## Saying it in an interview The strong answer names the inversion and then gets concrete. Something like: on this host class the precondition is free, because executing contributor-authored content is what the machine is for. That moves the flaw from post-compromise to initial access with an actor set of everyone who can open a pull request. Whether that matters depends on whether the build runs in a context holding project credentials and on whether the runner is reused across jobs. A candidate who says all that has demonstrated the general principle, which is that a precondition's weight is a property of the deployment, not of the record.
- Does making runners ephemeral remove the problem?It bounds it rather than removing it. An ephemeral runner still executes contributor content with whatever identity the job was given, so anything reachable during that job is reachable. What it removes is the carry-over: the caches, credential material and sessions that a persistent host leaves for the next job. That is a real reduction in what the position is worth, not a removal of the position.
- How would you say the same thing about a flaw marked 'adjacent network only' on those build hosts?Adjacency is decided by your topology, not by the advisory. If the build segment shares a VLAN with the laptop fleet, every laptop is adjacent, so the precondition is satisfied by the least trusted device population you own. The question to answer is not how hard adjacency is in general but which machines are already on that segment.
saying these in an interview costs you the question
- Reads 'local execution required' as always meaning post-compromise
- Classifies the flaw from the advisory without naming the host class
- Assumes only trusted maintainers can cause a build to run
- Ignores that a reused runner carries state between jobs
- Treats network adjacency as a property of the flaw rather than the topology