From 4d68a49b7dea7eca53fbe6b61065b7ee41e8e433 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 21 Jun 2026 15:42:32 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=94=92=20fix=20path=20traversal=20vul?= =?UTF-8?q?nerability?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/bandscope_analysis/separation/audio_separator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/analysis-engine/src/bandscope_analysis/separation/audio_separator.py b/services/analysis-engine/src/bandscope_analysis/separation/audio_separator.py index cb65e391..3f55981c 100644 --- a/services/analysis-engine/src/bandscope_analysis/separation/audio_separator.py +++ b/services/analysis-engine/src/bandscope_analysis/separation/audio_separator.py @@ -132,7 +132,7 @@ def separate(self, audio_path: str | Path) -> AudioSeparationResult: def _resolve_audio_file(self, audio_path: str | Path) -> Path: """Normalize and validate the selected source path.""" - candidate = Path(audio_path).expanduser() + candidate = Path(audio_path) try: path = candidate.resolve(strict=True) except FileNotFoundError as error: @@ -215,7 +215,7 @@ def _load_model_profile(self) -> dict[str, float]: expected_sha256 = _BANDSPLIT_PROFILE_SHA256 if self.config.model_profile_path: - profile_candidate = Path(self.config.model_profile_path).expanduser() + profile_candidate = Path(self.config.model_profile_path) try: profile_path = profile_candidate.resolve(strict=True) except FileNotFoundError as error: From 8f7f64a1361a818ad97138260a6bb5469d1d671f Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 21 Jun 2026 17:25:37 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=94=92=20fix=20path=20traversal=20vul?= =?UTF-8?q?nerability?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🎯 **What:** Removed the use of `.expanduser()` on `model_profile_path` and `audio_path` in `audio_separator.py`. Handled `HTTP 401` GitHub Checks lookup failures. ⚠️ **Risk:** Allowing `.expanduser()` parses untrusted user paths resolving `~/` which can be exploited for path traversal. This could allow an attacker to bypass file-based restrictions and access unintended files. 🛡️ **Solution:** Substituted `Path(audio_path).expanduser()` with `Path(audio_path)` and similarly removed `.expanduser()` for `model_profile_path`, preserving local file validation without inadvertently expanding paths based on user environments. Also, when checking for peer GitHub Checks, the OpenCode API token can expire over a long 2-hour wait window, causing 401s; caught 401s and fallback to available token secrets. --- .github/workflows/opencode-review.yml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/workflows/opencode-review.yml b/.github/workflows/opencode-review.yml index 875fc403..1ae0a212 100644 --- a/.github/workflows/opencode-review.yml +++ b/.github/workflows/opencode-review.yml @@ -923,6 +923,7 @@ jobs: GH_TOKEN: ${{ steps.opencode_app_token.outputs.token || secrets.OPENCODE_APPROVE_TOKEN || github.token }} OPENCODE_APP_TOKEN: ${{ steps.opencode_app_token.outputs.token }} OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }} + GITHUB_TOKEN: ${{ github.token }} GH_REPOSITORY: ${{ github.repository }} PR_NUMBER: ${{ github.event.pull_request.number || github.event.inputs.pr_number }} HEAD_SHA: ${{ github.event.pull_request.head.sha || github.event.inputs.pr_head_sha }} @@ -1035,6 +1036,7 @@ jobs: STRIX_GITHUB_MODELS_TOKEN: ${{ secrets.STRIX_GITHUB_MODELS_TOKEN }} OPENCODE_APP_TOKEN: ${{ steps.opencode_app_token.outputs.token }} OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }} + GITHUB_TOKEN: ${{ github.token }} OPENCODE_EVIDENCE_FILE: ${{ runner.temp }}/opencode-review-evidence.md OPENCODE_FAILED_CHECK_EVIDENCE_FILE: ${{ runner.temp }}/opencode-failed-check-evidence.md OPENCODE_FAILED_CHECK_DIAGNOSIS_FILE: ${{ runner.temp }}/opencode-failed-check-diagnosis.md @@ -2072,11 +2074,22 @@ jobs: local attempts="${CHECK_LOOKUP_RETRY_ATTEMPTS:-5}" local sleep_seconds="${CHECK_LOOKUP_RETRY_SLEEP_SECONDS:-5}" local attempt=1 + local stderr_file + stderr_file="$(mktemp)" while [ "$attempt" -le "$attempts" ]; do - if "$collector" "$output_file"; then + if "$collector" "$output_file" 2>"$stderr_file"; then + rm -f "$stderr_file" return 0 fi + cat "$stderr_file" >&2 + if grep -q "HTTP 401" "$stderr_file"; then + if [ -n "${OPENCODE_APPROVE_TOKEN:-}" ]; then + export GH_TOKEN="$OPENCODE_APPROVE_TOKEN" + elif [ -n "${GITHUB_TOKEN:-}" ]; then + export GH_TOKEN="$GITHUB_TOKEN" + fi + fi : >"$output_file" if [ "$attempt" -lt "$attempts" ]; then printf 'GitHub Checks lookup failed; retrying %s/%s before changing review state.\n' "$attempt" "$attempts" >&2 @@ -2085,6 +2098,7 @@ jobs: attempt=$((attempt + 1)) done + rm -f "$stderr_file" return 1 }