Assembling a provider endpoint address at run time keeps the key out of your repository. Which copies does it not close?
answer
- run-time assembly closes one copy
- the environment is inherited by children
- anything that stringifies prints the user info
- the reply can carry it back
- storage, printing and returning need separate fixes
basics
~20 sRun-time assembly closes only the copy in version control. The credential still sits in the job's process environment, inside an address object that prints its own user info, and possibly in a reply the far side sends back.
solid answer
~50 sBuilding the address in memory removes the copy that would otherwise live forever in the repository, and nothing more. Three copies remain, and they reach more sinks than the job log. The **process environment** holds both halves and is inherited by every child process the job starts, so anything that dumps the environment dumps the credential. The **address object** prints its user info whenever something stringifies it — a connection error, a report field, a re-run hint — so the leak arrives through diagnostics rather than through storage. And the **reply** is a genuine second location: a routing grid can build an address it returns to you out of the address you dialled, user info included. Selenium Grid's own node tests show both halves of that, deliberately dropping the credential-bearing transport value from the session reply while preserving the user info in the live-view address it hands back.
go deeper
Remember that a value can leak by being printed, not only by being stored. If a message mentions the endpoint, assume the credential is in it until you have checked.
Be able to list where the credential lives after assembly — environment, address object, reply, artefacts — and name a different control for each rather than one blanket answer.
Design for the return path: redact what arrives from the far side with the same helper as what you send, and audit which artefacts outlive the job's log.
Decide who owns this boundary across suites, because the failure is uniform and quiet: clean repositories, credentials in incident logs, and no single team that considers it theirs.
A team moves its hosted browser credentials out of a committed config file and into two protected pipeline variables, joined in memory at dial time. That is the right move, and it is worth being precise about what it achieved: it removed the copy that version control would have kept forever. The credential is still present in several other places, and the remaining leaks tend to arrive through diagnostics rather than through storage. ## The copy you closed Version control is the worst place for a secret because it is durable, widely readable, and hard to un-write: removing the line does not remove the history, and every clone already has it. Run-time assembly means the working address never exists as a file, so nothing gets committed and nothing has to be scrubbed later. That is the whole of the win. ## The copies you did not ### The job's process environment Both halves are in the environment of the process that reads them, and environments are inherited. Every child the job starts — a build tool, a shell, a container runtime, a crash reporter — can read them, and anything that dumps the environment for diagnosis writes them out in full. Assembly in memory does not touch this; the halves were injected before your code ran. ### The address object your code holds An address that carries user info prints that user info when it is turned into a string. This is not a subtle behaviour: the standard Java `URI` type includes the user-info component in `toString()`, so an address interpolated into any message appears with the credential in it. The places this actually happens are mundane: - a connection failure whose message quotes the URI it was trying to reach; - report metadata recording what the run connected to; - a "re-run with" hint printed to help a developer reproduce a failure locally; - a shell trace of the command that launched the run. Whether a given message is redacted is a property of the tool that wrote it, not of the address. Selenium's own HTTP client rewrites the user-info component before putting a request URI into a connection-error message. That is one client making a deliberate choice; the tool next to it in your stack may simply stringify. ### The reply from the far side This is the copy people miss, because the mental model is one-directional: the secret goes out, so close the outbound path and you are done. Remote ends also send addresses back — live-view, debugging and websocket endpoints that let you attach to a running session — and those are built from a base address on the remote side. Selenium Grid's node tests make the mechanism legible, and they cut both ways in the same file: | what the node does | with the credential | |---|---| | the transport value that carried the credential-bearing address | deliberately dropped from the session reply | | the live-view address built from a client-advertised remote address | returned with the user info intact | | the live-view address built from a configured public grid address, which wins over the advertised one | returned with that address's user info intact | So "assemble it at run time" closes the outbound copy only. Whatever your harness does with the session reply — logging it, attaching it to a report, storing it for a flaky-run investigation — is handling a value that may contain the credential you were careful about on the way out. ## What to do about each 1. **Environment.** Read the two halves once, as early as possible, and do not re-export them onward. Where the job starts child processes you control, do not pass the credential variables into them unless they genuinely need them. 2. **Address object.** Put one redaction helper in front of every diagnostic path and use the redacted form everywhere except the single call that dials. Make the redactor structural — rewrite the user-info component — rather than matching a value, and make it return a constant, never the original, on an address it could not parse. 3. **Reply.** Treat anything address-shaped in a session reply as potentially credential-bearing, and redact it with the same helper before it reaches a log or a report. This is the path that punishes a careless helper: a reply arrives as **text you parse**, so it can carry an authority your URL parser will not read as server-based — an underscore in a service name is enough — and a redactor that trusts the parser's "no user info here" hands the address straight back to you unchanged. 4. **The sinks all three reach.** Apply the same helper wherever your harness persists an address — a report, a trace file, a captured command line. Those outlive the job's log and are more widely readable. ## The habit worth forming Ask, for each place the credential could be, whether it is stored, printed or returned — and fix each with a different control: - storage is fixed by never writing the assembled form; - printing is fixed by a structural redactor in front of every sink; - returning is fixed by redacting what you receive as well as what you send. A team that has done only the first has removed the permanent copy and left the visible ones — the repository is clean, the incident log is not.
- Why would a grid return an address that still carries the credential you dialled with?Because the returned address has to be dialable by the same client, and the credential is part of what makes it work. Selenium Grid's node tests assert exactly that for its live-view address, while deliberately dropping the transport value that originally carried it — the two behaviours sit in the same test file and are both intentional.
- Your report attaches the full session reply for later debugging. What do you change?Run everything address-shaped through the same structural redactor before it is attached, and store the redacted form only. A report is usually more widely readable than a job log and lives longer, so an unredacted reply there has a larger audience and a longer exposure than the leak you were originally worried about.
saying these in an interview costs you the question
- Assembling the address at run time means the credential is no longer anywhere
- Secrets only leak outbound, so nothing coming back needs redacting
- Environment variables are private to the process that was given them
- A stack trace is internal output and does not count as disclosure
- If the client library did not print it, no tool in the stack will
- A redactor reporting no user info on a parsed reply has proved the reply is clean