What the Verified Suite Can Reach
Two fixes to what the verified test suite can reach: it no longer inherits your credentials, and a diff can no longer name a file outside the repository. Neither is exploitable without already being able to hand Refactron a diff or a test command, which is the normal mode of use. That is the point.
Two fixes to what the verified test suite can reach. Neither is exploitable without already being able to hand Refactron a diff or a test command, which is the normal mode of use. That is the point: the CI gate this tool is built for verifies untrusted pull requests, so “the attacker controls the input” is the design assumption, not the edge case.
The verified suite no longer inherits your credentials
Refactron runs your repository's own test suite, and the diff under verification defines that suite. It was handed the full parent environment. Reproduced: a test read REFACTRON_TOKEN, GITHUB_TOKEN, NPM_TOKEN and AWS_SECRET_ACCESS_KEY in plaintext. This matters most in the deployment Refactron is built for, a CI gate holding the credentials of the repository being protected.
Credentials are now removed from the environment of every spawn that executes your suite. This is a denylist: the common names, plus anything ending in _TOKEN, _SECRET, _API_KEY, _PASSWORD or _CREDENTIALS. PATH, HOME, VIRTUAL_ENV and the rest of your toolchain are untouched.
A diff can no longer name a file outside the repository
The path came from the diff's own +++ header and was read with no containment check, so a diff naming ../../../.ssh/id_rsa caused Refactron to open it. The shadow tree blocked the resulting write, but the read had already happened, and whether the patch applied was an oracle for the file's contents. Containment now runs at intake, before the first read.
Both fixes shipped with a bypass of themselves
Both were found in review of this release and fixed in it. Recording that plainly, because the pattern is the lesson: a redaction that covers two of three spawns is not a redaction, and a containment check that is lexical while the read follows symlinks is not containment.
- The coverage probe was not redacted.
-m coverage --versionruns with the project root as cwd, and-mputs cwd onsys.path, so acoverage.pyplanted at the repository root shadows the real module and the diff under verification executes as us. That probe passed no environment at all and inherited everything, while the two coverage spawns after it were correctly redacted. The env parameter is now required rather than optional, so a call site that omits it fails to compile. - Diff paths now resolve symlinks before they are trusted. The containment check was lexical, but
readFilefollows links, sorepo/link -> /secretsletlink/creds.txtpass and read outside anyway. Reproduced as an oracle: a diff whose removal line guessed the target's contents was accepted, while a wrong guess reported “diff did not apply”, which discloses the file one guess at a time. Both cases now return the same message.
Changed
SECURITY.md was rewritten. The previous version described the refactoring product removed in 0.4.0 and stopped its supported-versions table at 0.2.x. It now documents what actually ships, records GHSA-q3vj-5qq5-m84g, and adds a section the old policy lacked: what Refactron explicitly does not defend.
- We do not sandbox your test suite.
- The MCP server has no authentication, because a stdio transport's trust boundary is the process spawn.
SAFEis not a proof of correctness.- Narrowing detection is a strong check, not a guarantee.
