Skip to content

🛡️ Sentinel: [CRITICAL] 프로젝트 ID 입력의 경로 탐색(Path Traversal) 취약점 수정#494

Closed
seonghobae wants to merge 3 commits into
developfrom
fix-path-traversal-project-id-215616366698651889
Closed

🛡️ Sentinel: [CRITICAL] 프로젝트 ID 입력의 경로 탐색(Path Traversal) 취약점 수정#494
seonghobae wants to merge 3 commits into
developfrom
fix-path-traversal-project-id-215616366698651889

Conversation

@seonghobae

Copy link
Copy Markdown
Collaborator

이 PR은 경로 탐색(Path Traversal) 취약점을 수정하는 보안 패치를 포함합니다.

project_id 필드가 내부 식별자로 쓰이지만 사용자 IPC 페이로드로부터 입력될 수 있다는 점을 고려하여, 해당 필드에 .., /, \와 같은 디렉토리 순회 문자가 포함되어 있을 경우 이를 거부하는 방어적 코드를 apps/desktop/src-tauri/src/main.rsparse_request_payload에 추가했습니다. 이를 통해 app_owned_root에서 예상하지 못한 디렉토리로의 접근을 원천 차단합니다.

모든 변경 사항은 새롭게 추가된 단위 테스트를 포함하여 성공적으로 검증되었습니다.


PR created automatically by Jules for task 215616366698651889 started by @seonghobae

🚨 Severity: CRITICAL
💡 Vulnerability: `apps/desktop/src-tauri/src/main.rs`의 `app_owned_root` 함수와 페이로드 파싱 단계에서 사용자 입력인 `project_id`에 대한 검증이 부족하여 `../` 등을 통한 경로 탐색이 가능했습니다.
🎯 Impact: 악의적인 `project_id`를 조작하여 의도된 앱 캐시 및 임시 디렉토리 구조를 벗어나 시스템 내의 다른 디렉토리에 접근하거나 파일을 덮어쓸 수 있는 위험이 있었습니다.
🔧 Fix: `project_id`에 `..`, `/`, `\` 문자가 포함되어 있는지 검사하는 로직을 `parse_request_payload`에 추가하여 안전하지 않은 입력을 즉시 거부하도록 변경했습니다.
✅ Verification: 단위 테스트(`parse_request_payload_rejects_path_traversal`)를 추가하여 취약점이 완화되었는지 검증하였으며, 전체 테스트 스위트를 통해 정상 동작을 확인했습니다.
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings July 1, 2026 02:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the desktop Tauri IPC surface against path traversal by rejecting unsafe projectId values before they can be used as filesystem path segments, and it documents the security learning in the Jules Sentinel log.

Changes:

  • Add defensive validation rejecting .., /, and \ in projectId (IPC payload parsing and app_owned_root).
  • Add unit tests ensuring traversal-like projectId payloads are rejected.
  • Update the Sentinel security note describing the vulnerability and prevention guidance.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
apps/desktop/src-tauri/src/main.rs Adds projectId path traversal validation in both request parsing and app-owned path construction; adds tests for rejection cases.
.jules/sentinel.md Records the path traversal security lesson and prevention guidance for future reference.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +381 to +383
if project_id.contains("..") || project_id.contains('/') || project_id.contains('\\') {
return Err("Invalid project ID: path traversal detected.".to_string());
}
Comment on lines +564 to 570
if project_id.trim().is_empty()
|| project_id.contains("..")
|| project_id.contains('/')
|| project_id.contains('\\')
{
return Err("Invalid analysis job request: invalid field 'projectId'".into());
}
Comment on lines +1340 to +1357
#[test]
fn parse_request_payload_rejects_path_traversal_forward_slash() {
let payload = json!({
"sourceKind": "local_audio",
"projectId": "/malicious-project",
"sourceLabel": "My Song",
"roleFocus": ["lead-vocal"],
});

let result = parse_request_payload(payload);

assert!(result.is_err());
assert_eq!(
result.unwrap_err(),
"Invalid analysis job request: invalid field 'projectId'"
);
}

Comment thread .jules/sentinel.md
Comment on lines +2 to +4
**Vulnerability:** The `project_id` field in the analysis payload is supplied by the user (or remote client) and is used directly in `app_owned_root` (`base_root.join(project_id)`) to determine the directory for project caching, temp space, and data. This allows an attacker to pass `../` in the `project_id` string, causing path traversal and letting them access or overwrite directories outside the designated app boundaries.
**Learning:** Even internal-looking identifiers (like `project_id`) are attack vectors if they originate from user input or IPC payloads. The codebase's `app-security.md` rule to "Defend against path traversal and parent directory escape" was missed in this initial implementation.
**Prevention:** Always validate and sanitize all identifier fields that get concatenated into paths. Explicitly reject payloads where the identifier contains path traversal characters like `..`, `/`, or `\`. Add tests specifically validating rejection on paths containing these sequences to maintain test coverage and security posture.
@opencode-agent

opencode-agent Bot commented Jul 1, 2026

Copy link
Copy Markdown

OpenCode Review Overview

  • Head SHA: 287b81e7d5ab636633f6a60ea7289f831cc053e0
  • Workflow run: 28489962955
  • Workflow attempt: 1
  • Gate result: CHECK_FAILED (approval step)

Pull request overview

OpenCode cannot approve yet because required coverage evidence did not pass.

Check outcome

1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence

  • Problem: The OpenCode approval path reached an APPROVE control result while the separate coverage-evidence job result was failure.

  • Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.

  • Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports success with required evidence or explicit no-source not-applicable evidence.

  • Regression test: Keep the approval branch checking needs.coverage-evidence.result == success before posting APPROVE, but leave the PR review unchanged for coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence.

  • Result: CHECK_FAILED

  • Reason: coverage-evidence result was failure, so required test/docstring evidence was not proven for current head 287b81e7d5ab636633f6a60ea7289f831cc053e0.

  • Head SHA: 287b81e7d5ab636633f6a60ea7289f831cc053e0

  • Workflow run: 28489962955

  • Workflow attempt: 1

Coverage evidence

Coverage Evidence

  • Head SHA: 287b81e7d5ab636633f6a60ea7289f831cc053e0
  • Required test evidence: supported repository test suites must pass.
  • Required docstring evidence: repository-owned docstring gates must pass when configured; otherwise docstring coverage is advisory.

Rust coverage tooling (cargo-llvm-cov)

    Updating crates.io index
 Downloading crates ...
  Downloaded cargo-llvm-cov v0.8.7
  Installing cargo-llvm-cov v0.8.7
    Updating crates.io index
    Updating crates.io index
 Downloading crates ...
  Downloaded cfg-if v1.0.4
  Downloaded serde_spanned v1.1.1
  Downloaded shell-escape v0.1.5
  Downloaded xattr v1.6.1
  Downloaded quick-xml v0.39.4
  Downloaded shared_child v1.1.1
  Downloaded aho-corasick v1.1.4
  Downloaded rustc-demangle v0.1.27
  Downloaded serde_derive v1.0.228
  Downloaded quote v1.0.45
  Downloaded itoa v1.0.18
  Downloaded serde v1.0.228
  Downloaded memchr v2.8.0
  Downloaded toml_parser v1.1.2+spec-1.1.0
  Downloaded walkdir v2.5.0
  Downloaded cargo-config2 v0.1.44
  Downloaded toml v1.1.2+spec-1.1.0
  Downloaded os_pipe v1.2.3
  Downloaded glob v0.3.3
  Downloaded zmij v1.0.21
  Downloaded tar v0.4.45
  Downloaded rustix v1.1.4
  Downloaded regex-syntax v0.8.10
  Downloaded winnow v1.0.2
  Downloaded duct v1.1.1
  Downloaded unicode-ident v1.0.24
  Downloaded errno v0.3.14
  Downloaded bitflags v2.11.1
  Downloaded toml_datetime v1.1.1+spec-1.1.0
  Downloaded ruzstd v0.8.3
  Downloaded serde_json v1.0.149
  Downloaded syn v2.0.117
  Downloaded serde_core v1.0.228
  Downloaded opener v0.8.4
  Downloaded regex v1.12.3
  Downloaded lcov2cobertura v1.0.9
  Downloaded autocfg v1.5.0
  Downloaded fs-err v3.3.0
  Downloaded lexopt v0.3.2
  Downloaded filetime v0.2.29
  Downloaded shared_thread v0.2.0
  Downloaded same-file v1.0.6
  Downloaded termcolor v1.4.1
  Downloaded camino v1.2.2
  Downloaded proc-macro2 v1.0.106
  Downloaded regex-automata v0.4.14
  Downloaded anyhow v1.0.102
  Downloaded bstr v1.12.1
  Downloaded libc v0.2.186
  Downloaded linux-raw-sys v0.12.1
   Compiling memchr v2.8.0
   Compiling serde_core v1.0.228
   Compiling libc v0.2.186
   Compiling proc-macro2 v1.0.106
   Compiling aho-corasick v1.1.4
   Compiling regex-syntax v0.8.10
   Compiling unicode-ident v1.0.24
   Compiling quote v1.0.45
   Compiling rustix v1.1.4
   Compiling autocfg v1.5.0
   Compiling winnow v1.0.2
   Compiling regex-automata v0.4.14
   Compiling bitflags v2.11.1
   Compiling linux-raw-sys v0.12.1
   Compiling anyhow v1.0.102
   Compiling zmij v1.0.21
   Compiling serde v1.0.228
   Compiling toml_datetime v1.1.1+spec-1.1.0
   Compiling serde_spanned v1.1.1
   Compiling toml_parser v1.1.2+spec-1.1.0
   Compiling fs-err v3.3.0
   Compiling syn v2.0.117
   Compiling cfg-if v1.0.4
   Compiling serde_json v1.0.149
   Compiling camino v1.2.2
   Compiling filetime v0.2.29
   Compiling regex v1.12.3
   Compiling bstr v1.12.1
   Compiling xattr v1.6.1
   Compiling toml v1.1.2+spec-1.1.0
   Compiling serde_derive v1.0.228
   Compiling os_pipe v1.2.3
   Compiling shared_child v1.1.1
   Compiling quick-xml v0.39.4
   Compiling shared_thread v0.2.0
   Compiling same-file v1.0.6
   Compiling rustc-demangle v0.1.27
   Compiling itoa v1.0.18
   Compiling lcov2cobertura v1.0.9
   Compiling cargo-config2 v0.1.44
   Compiling walkdir v2.5.0
   Compiling duct v1.1.1
   Compiling tar v0.4.45
   Compiling opener v0.8.4
   Compiling shell-escape v0.1.5
   Compiling glob v0.3.3
   Compiling ruzstd v0.8.3
   Compiling termcolor v1.4.1
   Compiling lexopt v0.3.2
   Compiling cargo-llvm-cov v0.8.7
    Finished `release` profile [optimized] target(s) in 1m 04s
  Installing /home/runner/.cargo/bin/cargo-llvm-cov
   Installed package `cargo-llvm-cov v0.8.7` (executable `cargo-llvm-cov`)
  • Result: PASS

Rust test coverage

  • Result: FAIL
  • Reason: Rust files changed, but no root Cargo.toml was found.
  • Fix: add or point to the Cargo workspace manifest and run cargo coverage from that workspace.

Coverage Decision

  • Result: FAIL
  • Test evidence: not proven passing
  • Docstring evidence: not proven passing when configured
  • Failure count: 1

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (2 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (2 files)"]
  R1 --> V1["required checks"]
Loading

@seonghobae

Copy link
Copy Markdown
Collaborator Author

현재 head의 중앙 coverage-evidence 실패 원인을 Actions log에서 확인했습니다.

원인:

  • Rust test coverage 단계가 실패했습니다.
  • 로그의 직접 원문: Rust files changed, but no root Cargo.toml was found.
  • 중앙 coverage 계약은 Rust 파일 변경 시 cargo llvm-cov --workspace --all-features --fail-under-lines 100 --show-missing-lines를 실행할 수 있는 workspace manifest를 기대합니다.

수정 방향:

  • PR이 Rust/Tauri 쪽 변경을 포함한다면, coverage job이 찾을 수 있는 root Cargo.toml 또는 명시적인 workspace/coverage 실행 계약이 필요합니다.
  • 실제 Rust 변경이 의도된 것이 아니라면 변경 범위에서 Rust 파일을 제거하고, 관련 JS/Python 테스트만 통과하도록 정리해야 합니다.

참고: 이 실패는 원래 OpenCode가 REQUEST_CHANGES 리뷰로 설명해야 하는데, 현재 중앙 workflow가 coverage-evidence 실패 시 PR review를 게시하지 않고 job 실패만 남기는 문제가 있어 ContextualWisdomLab/.github#255에서 보완 중입니다. 그 PR이 반영되면 같은 유형은 리뷰 본문으로 게시되도록 바뀝니다.

🚨 Severity: CRITICAL
💡 Vulnerability: `apps/desktop/src-tauri/src/main.rs`의 `app_owned_root` 함수와 페이로드 파싱 단계에서 사용자 입력인 `project_id`에 대한 검증이 부족하여 `../` 등을 통한 경로 탐색이 가능했습니다.
🎯 Impact: 악의적인 `project_id`를 조작하여 의도된 앱 캐시 및 임시 디렉토리 구조를 벗어나 시스템 내의 다른 디렉토리에 접근하거나 파일을 덮어쓸 수 있는 위험이 있었습니다.
🔧 Fix: `project_id`에 `..`, `/`, `\` 문자가 포함되어 있는지 검사하는 로직을 `parse_request_payload`에 추가하여 안전하지 않은 입력을 즉시 거부하도록 변경했습니다.
✅ Verification: 단위 테스트(`parse_request_payload_rejects_path_traversal`)를 추가하여 취약점이 완화되었는지 검증하였으며, 전체 테스트 스위트를 통해 정상 동작을 확인했습니다.
@seonghobae

Copy link
Copy Markdown
Collaborator Author

현재 \ 기준으로 이 PR은 자동 update-branch 대상이 아니라 merge conflict 상태입니다. 임시 clone에서 \로 재현했습니다.

충돌 파일:

  • `docs/design-system/README.md`
  • `docs/design-system/component-contract.md`
  • `docs/design-system/figma-to-code-workflow.md`

권장 처리:

  1. \
  2. PR branch에서 \ 또는 \
  3. 위 파일의 conflict marker를 제거하고, 의도한 변경과 최신 design-system 문서/desktop 변경을 함께 보존
  4. 로컬 테스트와 coverage를 다시 실행
  5. 같은 PR branch로 push

이 상태에서는 OpenCode/auto-merge가 판단으로 해결할 수 없고, 사람이 충돌 내용을 선택해야 합니다.

@seonghobae

Copy link
Copy Markdown
Collaborator Author

정정: 바로 위 conflict 안내 댓글은 shell quoting 문제로 inline code 일부가 누락됐을 수 있습니다. 현재 develop 기준 merge simulation 결과는 아래가 정확합니다.

자동 update-branch 대상이 아니라 merge conflict 상태입니다. 임시 clone에서 git merge --no-commit --no-ff origin/develop 로 재현했습니다.

충돌 파일:

  • docs/design-system/README.md
  • docs/design-system/component-contract.md
  • docs/design-system/figma-to-code-workflow.md

권장 처리:

  1. git fetch origin develop
  2. PR branch에서 git merge origin/develop 또는 git rebase origin/develop
  3. 위 파일의 conflict marker를 제거하고, 의도한 변경과 최신 design-system/desktop 변경을 함께 보존
  4. 로컬 테스트와 coverage를 다시 실행
  5. 같은 PR branch로 push

이 상태에서는 OpenCode/auto-merge가 판단으로 해결할 수 없고, 사람이 충돌 내용을 선택해야 합니다.

@seonghobae

Copy link
Copy Markdown
Collaborator Author

Superseding this PR with a focused clean branch: #527.

Reason: this branch currently has mergeStateStatus=DIRTY, unresolved review threads, prior coverage-evidence failure, and a 60-file diff that mixes the project-ID traversal fix with central workflow/design/package churn. #527 carries the same security intent against develop in two files only, addresses the Copilot precision/backslash/sentinel-note feedback, and includes local verification in the PR body.

@seonghobae

Copy link
Copy Markdown
Collaborator Author

Closed in favor of #527, which isolates the project-ID path traversal fix on a clean develop branch.

@seonghobae seonghobae closed this Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants