Your machine's local credential endpoint is reachable from a link-preview feature that fetches any caller-supplied URL — what does the attacker get?
answer
- the feature fetches whatever it is told
- locality was the only check
- the bug supplies locality for free
- bearer material, nothing binds it
- expiry limits replay, not the window
basics
~20 sThe machine's whole credential set — identifier, secret and session token — in plain text, usable from anywhere until it expires. Nothing binds it to the machine, so the attacker then calls the platform directly as that workload.
solid answer
~40 sThe preview feature satisfies the endpoint's only precondition on the attacker's behalf: the request genuinely originates on that machine. Locality was the authorization, and the bug supplies locality. What comes back is a usable credential set, which is returned into the preview card, echoed in an error, or written somewhere the attacker can read. It is **bearer** material — no proof of possession, no binding to a source address — so it works from the attacker's own machine against the platform's public API, as that workload, until it lapses. The short lifetime bounds replay after you close the hole; it bounds neither what is done inside the window nor the attacker's ability to fetch a fresh set while the hole is open.
go deeper
Recall the shape of the risk: a feature that fetches a caller's URL can be pointed at the machine's own credential endpoint, and what comes back is a usable credential rather than a harmless page.
Explain why the endpoint's locality check is satisfied: the request really does originate on the machine, and the returned credential is bearer material with nothing tying it to where it was fetched.
Show the incident reasoning: what the short lifetime bounds and what it does not, why the durable fix is at the endpoint rather than in the fetching code, and which platform-side signal tells you the credential was used.
Argue the standard: machines that never call the platform should not answer on that endpoint at all, and the hardened path should be required fleet-wide rather than left to each team's fetcher to defend against.
## Why the endpoint is the prize A request-forging bug is any place where your server fetches a URL that a caller influences. The shapes are familiar: - a link preview that renders a submitted address - a webhook tester that calls a configurable target - an image or document importer that pulls from a supplied location - a health check whose endpoint is settable in configuration - anything that follows a redirect chain a caller can steer The bug's value to an attacker is decided entirely by what the server can reach that they cannot. On a rented machine the highest-value item on that list is the local credential endpoint, because it is designed to answer anything that asks from the machine, and what it answers with is an identity. The feature satisfies the endpoint's precondition for the attacker. The request really does originate on that machine. Locality was the check, and the bug supplies locality on demand. ## The chain 1. The attacker submits a link whose host resolves to the endpoint's link-local address. 2. The server fetches it, exactly as the feature was built to do. 3. The endpoint answers with the machine's credential set. 4. The response reaches the attacker — rendered into the preview card, echoed in an error message, written to a log they can read, or inferred slowly if none of those. 5. The attacker signs calls to the platform's public API with it, from their own machine, as that workload. Step 5 is the one that surprises people, and it is the one worth saying out loud in an interview. ## Bearer, not bound The credential set is **bearer** material: possession is sufficient. It carries no proof of possession, no binding to a source address, no binding to a process, and no channel binding. The platform validates the signature and the expiry, and has no basis for noticing that the caller is now somewhere else entirely. This is why "but the endpoint is only reachable from the machine" is a statement about the **endpoint**, not about the **credential**. The moment the value leaves the machine, the locality property that protected it is gone with it, and it was never a property of the value in the first place. ## What the short lifetime does and does not limit | | Bounded by the short lifetime | Not bounded by it | |---|---|---| | Replay of that value once the bug is closed | yes — it stops being accepted | — | | Actions taken inside the window | — | a copied data store, a changed configuration, a deleted resource is permanent | | Continued access while the bug is open | — | the attacker simply fetches a fresh set | | Access after the identity is detached | yes, once the issued set lapses | — | The honest summary: expiry is a decay timer on a stolen value, and it is genuinely worth having. It is not containment while the hole is still open, and it does nothing about what has already been done. ## Where the durable fix lives Denying that one address inside the fetching code is worth doing and is not where this ends: a redirect, a hostname resolving to the same address, or a different local-only service will route around a single blocked string. The defences that survive contact live at the endpoint itself: - **require the hardened request path**, so a one-way fetch cannot complete the exchange at all - **set a reply hop limit**, so callers a routing hop away lose the answer - **switch the endpoint off** on machines whose workloads never call the platform Separately, how much the stolen credential is worth is decided by what the attached identity is permitted to do. That is a different lever from this one, and it is the difference between an incident and a catastrophe. ## Detecting it The signal is platform-side, and it is available precisely because the attacker is using **your** identity, which is recorded as your identity. What you look for is calls under that workload's identity that the workload does not make: broad listing and enumeration that a checkout service has no reason to produce, actions on resources it never touches, and calls arriving from somewhere the workload has never called from. The last of those is the strongest signal available, because the credential's bearer nature is the only reason the calls are coming from anywhere else.
- The credential expires in a few hours — does that contain the incident?It bounds replay of that particular value after you close the bug, which is real but narrow. It does not undo anything done inside the window, and while the forging bug still works the attacker just fetches another set whenever the current one lapses. Treat expiry as shortening the tail of an incident, never as the control that ends it.
- What do you pull first to find out whether the credential was actually used?The platform-side record of calls made under that workload's identity, filtered to actions the workload does not perform and to source locations it never calls from. Because the credential is bearer material with no binding, an attacker using it shows up as your own identity behaving unlike itself — which is the only handle the theft leaves.
- Why is blocking the endpoint's address in the fetcher not the durable fix?It is one string in one code path. A redirect, a hostname that resolves to the same address, a second feature that fetches URLs, or another local-only service all route around it, and the next such feature ships without the check. The durable fixes sit at the endpoint — requiring the hardened request path, limiting reply hops, or not answering on that machine at all — because they hold regardless of which code does the fetching.
saying these in an interview costs you the question
- Says the credential only works from the machine it was issued to
- Believes a short lifetime contains an incident on its own
- Thinks the endpoint returns a description of permissions, not a credential
- Claims closing the one feature closes the whole class
- Assumes the attacker must run code on the machine to use it