How do you prepare an embargoed security fix without the public repository revealing it?
answer
- small circle, not the whole org
- branch from the released tag
- one commit, no ticket link
- test the invariant, not the payload
- build logs and artifacts leak too
basics
~20 sDevelop it out of public view: a private fork with a per-issue access list, branched from the released tag, landing as one squashed commit with a neutral message and a test that proves the fix without shipping a payload.
solid answer
~40 sWork in a private fork or private mirror of the repository whose read access is scoped to the few people who must write, review or test the fix — not the whole organisation. Branch from the released tag rather than from the mainline, so the change is small and applies cleanly to the lines you will backport to. Plan how it will look in public: one squashed commit at release time with a message that is honest but not a tutorial, no link to a ticket whose title names the flaw, and a regression test written to assert the correct behaviour rather than to embed a working exploit. Then check the edges — build logs, pre-release artifacts, auto-closed public issues and dependency bumps all leak from an otherwise private branch.
go deeper
Know the shape: the fix is written somewhere the public cannot read, and it becomes visible only when the fixed release exists. Being able to name a private fork and a squashed, uninformative commit is enough at this level.
Explain the mechanics and the reasoning behind each: branching from the released tag, squashing, keeping ticket references private, and writing a regression test that proves the invariant rather than shipping a payload.
Demonstrate that you look past the branch to the leak paths around it — build logs, candidate artifacts, docs and translation pipelines, dependency bumps, chat integrations — and that you keep the diff minimal under pressure.
Own the access model. Argue for per-issue spaces with named, time-boxed access over a standing security repository, separate reading the fix from testing a build, and be able to reconstruct afterwards who could have leaked it.
## Goal Between the report landing and the release going out, the fix must exist, be reviewed, be tested on every line you intend to ship it on, and be invisible to anyone outside a small circle. Those pull in opposite directions, and most of the craft here is managing that tension. ## Where the work happens The practical pattern is a **private fork or private mirror** of the repository, created for this issue, with an explicit access list. Many forges provide a private workspace attached to a draft advisory for exactly this; a self-hosted private mirror works equally well. What matters is not the mechanism but two properties: the code is not publicly readable, and the set of people who can read it is chosen per issue rather than inherited from a standing group. **Branch from the released tag, not from the mainline.** A fix built on top of months of unreleased mainline changes is hard to backport, hard to review under pressure, and hard to ship as a patch release that consumers can take without also taking unrelated behaviour changes. Branching from the tag keeps the change minimal and gives you a base that already resembles each supported line. ## Designing what the public will eventually see Decide the public shape of the change *while you write it*, because you only get one chance to land it: - **One squashed commit** at release time, rather than the twelve exploratory commits that actually produced it. Intermediate commits narrate the discovery — a failed fix, a widened check, a revert — and that narration is a tutorial on the flaw. - **A commit message that is accurate but not instructional.** "Harden input validation in the configuration reader" before release; the advisory carries the detail afterwards. Deliberately misleading messages are a different thing and corrode trust — aim for uninformative, not false. - **No public ticket reference.** Track the work in the private space. A public issue whose title is the vulnerability, closed by the commit, defeats everything else you did. - **A regression test that does not double as a proof-of-concept.** Test the invariant ("unknown types are rejected") rather than shipping the crafted payload that exercises the bug. Where that is impossible, land the test with or after the release, not ahead of it. Take a framework fixing a deserialization flaw as the worked case. The public repository is mirrored by bots within seconds of a push, so the discipline is not theatre: a single commit introducing a class allow-list, with a test that feeds it a gadget chain, is a complete attack write-up for an anonymous observer who has no access to anything else you own. ## The leaks that survive a private branch People get the branch right and lose on the periphery: - **CI and build logs.** A build triggered from the private branch may publish logs, test names or artifacts to a place the public can read. Route embargoed builds to a private runner and a private log sink. - **Pre-release artifacts.** A candidate build pushed to a publicly readable pre-release or staging channel is downloadable and diffable. - **Dependency changes.** Bumping an upstream library whose own release notes name the flaw announces it for you. - **Documentation and translation pipelines.** Strings queued for translation, or docs rebuilt from the private branch, have escaped more than one embargo. - **Third-party notifications.** Chat integrations, mail relays and project-management syncs attached to the fork may fan the diff out to a wider audience than the fork's access list. ## Who gets to see it The circle should be as small as the work allows — and the work usually needs more people than the person writing the patch: a reviewer with real context, someone to build and test each supported line, sometimes the reporter, who is often the only person able to confirm the fix actually closes the flaw they found. Confirming a fix with the reporter is normal and valuable; send them a patch or a build rather than granting repository access. The failure mode is a *standing* security repository whose read list has quietly grown to include everyone who ever needed it — contractors, former team members, an entire engineering group. Fifty people with read access is not an embargo; it is a press release with a delay. Prefer per-issue spaces with named, time-boxed access, keep the ability to *read the fix* separate from the ability to *test a build* (many testers need only the binary), and be able to answer afterwards who could see it. If the fix leaks, that list is the investigation. ## A note on scope creep Under embargo the temptation is to fix the whole class of problem, refactor the offending module, or slip in unrelated cleanups because the branch is open anyway. Resist it. A larger diff is harder to review with few reviewers, harder to backport, more likely to break consumers taking an urgent patch release, and — because it touches more code — often more revealing rather than less.
- Fifty contractors have read access to the security repository where the patch branch lives. How do you shrink that without blocking the people who must test?Stop using a standing repository. Create a per-issue private space and invite named people with time-boxed access, splitting two needs apart: reading the source and testing a build. Most testers only need the candidate binary, which you can hand them without repository access. Keep an access log so that if it leaks you can say who could see it.
- The reporter wants to verify your fix before release. Is that safe?It is normal and usually worth it — they found the flaw and are often the only person who can confirm the patch really closes it rather than moving it. Share a patch file or a candidate build out of band instead of granting repository access, and be explicit that the material is still embargoed.
- Should the commit message be deliberately misleading to hide the fix?No. Aim for uninformative, not false. "Harden input validation in the configuration reader" is fine; a message claiming it is a performance change is a lie your users will find in the history later, and it damages the trust that makes coordinated disclosure work at all. The advisory supplies the real detail at release.
- Why branch from the released tag rather than from the mainline?Because the fix has to ship as a patch release that consumers can take urgently without inheriting unrelated mainline changes, and because a tag-based diff usually applies cleanly to each supported line you plan to backport to. It also keeps the change small enough to review properly with the handful of people cleared to see it.
saying these in an interview costs you the question
- Keeps the branch private but publishes CI logs
- Writes the flaw into the commit message
- Merges to mainline early and delays the tag
- Grants the whole organisation read access
- Ships the exploit payload as the regression test
- Bundles a refactor into the embargoed patch