Skip to content

Commit f02e100

Browse files
committed
refactor(exec-approvals): drop dead trustedSymlinkConsumed flag
Greptile review on #72572: the flag was logically dead — it can only be set when i === 0, and the loop never revisits i === 0, so by the time it could be true, !isImmediateRootChild is already true. Removing it makes the at-most-one-hop invariant rest visibly on the !isImmediateRootChild guard. Behavior is unchanged; existing tests still cover the single-hop allow, double-hop reject, and untrusted-target reject paths.
1 parent 4bab657 commit f02e100

1 file changed

Lines changed: 6 additions & 6 deletions

File tree

src/infra/exec-approvals.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -264,23 +264,23 @@ function assertNoSymlinkPathComponents(targetPath: string, trustedRoot: string):
264264
// — the common GNU Stow / chezmoi dotfile layout. Once we follow it we
265265
// continue traversal from the realpath target with the same per-segment
266266
// symlink rejection, so deeper symlinks inside the resolved tree remain
267-
// disallowed. Trust requires the symlink target to be (a) owned by the
268-
// current effective user and (b) not group/other writable, matching the
269-
// hardening intent of #64050 / #72377.
270-
let trustedSymlinkConsumed = false;
267+
// disallowed (the loop never revisits i === 0, so the at-most-one-hop
268+
// invariant follows directly from the !isImmediateRootChild guard below).
269+
// Trust requires the symlink target to be (a) owned by the current
270+
// effective user and (b) not group/other writable, matching the hardening
271+
// intent of #64050 / #72377.
271272
for (let i = 0; i < segments.length; i += 1) {
272273
const segment = segments[i];
273274
current = path.join(current, segment);
274275
try {
275276
const stat = fs.lstatSync(current);
276277
if (stat.isSymbolicLink()) {
277278
const isImmediateRootChild = i === 0;
278-
if (!isImmediateRootChild || trustedSymlinkConsumed) {
279+
if (!isImmediateRootChild) {
279280
throw new Error(`Refusing to traverse symlink in exec approvals path: ${current}`);
280281
}
281282
const realTarget = fs.realpathSync(current);
282283
assertTrustedSymlinkTarget(current, realTarget);
283-
trustedSymlinkConsumed = true;
284284
current = realTarget;
285285
}
286286
} catch (err) {

0 commit comments

Comments
 (0)