From 6baf04be32e89a0d11d9d036d64152c8f6925751 Mon Sep 17 00:00:00 2001 From: "aikido-autofix[bot]" <119856028+aikido-autofix[bot]@users.noreply.github.com> Date: Tue, 9 Jun 2026 14:41:16 +0000 Subject: [PATCH 1/2] fix(security): autofix Potential file inclusion attack via reading file --- scripts/mutation_gate.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/mutation_gate.py b/scripts/mutation_gate.py index 1a7c281d..4b27ffe2 100644 --- a/scripts/mutation_gate.py +++ b/scripts/mutation_gate.py @@ -18,6 +18,7 @@ import ast import contextlib import importlib.util +import os import re import subprocess import sys @@ -255,6 +256,10 @@ def _invalidate_bytecode(path: Path) -> None: def _survives( path: Path, tree: ast.Module, src: str, mutant: _Mutant, data: coverage.CoverageData ) -> bool: + base_real = os.path.realpath(_PKG) + target_real = os.path.realpath(path) + if os.path.commonpath([base_real, target_real]) != base_real: + raise Exception("Invalid file path") mutant.apply() try: path.write_text(ast.unparse(tree), encoding="utf-8") From 4ae50940a586931386c6fd3b8727a7817fce05bb Mon Sep 17 00:00:00 2001 From: Alex Kroman Date: Tue, 9 Jun 2026 07:48:24 -0700 Subject: [PATCH 2/2] fix(mutation-gate): make Aikido path guard idiomatic Rework the auto-generated path-traversal guard in _survives: use pathlib (path.resolve().is_relative_to(...)) instead of os.path, which the repo's ruff PTH rules reject, and raise a descriptive ValueError rather than a bare Exception. Drops the added `import os`. Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/mutation_gate.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/mutation_gate.py b/scripts/mutation_gate.py index 4b27ffe2..6671b803 100644 --- a/scripts/mutation_gate.py +++ b/scripts/mutation_gate.py @@ -18,7 +18,6 @@ import ast import contextlib import importlib.util -import os import re import subprocess import sys @@ -256,10 +255,11 @@ def _invalidate_bytecode(path: Path) -> None: def _survives( path: Path, tree: ast.Module, src: str, mutant: _Mutant, data: coverage.CoverageData ) -> bool: - base_real = os.path.realpath(_PKG) - target_real = os.path.realpath(path) - if os.path.commonpath([base_real, target_real]) != base_real: - raise Exception("Invalid file path") + # Safety: only ever rewrite files inside the package under test. The file list + # comes from `git diff`, so this can't normally escape, but guard against a path + # that resolves outside aai_cli/ before we write to it. + if not path.resolve().is_relative_to(Path(_PKG).resolve()): + raise ValueError(f"refusing to mutate a file outside {_PKG}/: {path}") mutant.apply() try: path.write_text(ast.unparse(tree), encoding="utf-8")