Skip to main content
Glama

fsguard-mcp

PyPI

모든 작업을 허용된 디렉터리 트리 안으로 제한하는 filesystem + git MCP 서버입니다. 기준은 문자열 접두사 매칭이 아니라 심볼릭 링크를 해석하는 경로 포함(containment) 검증입니다.

왜 존재하는가

Anthropic의 공식 filesystem 및 git MCP 서버(@modelcontextprotocol/server-filesystem, modelcontextprotocol/servers의 일부, 89.7k★)는 10개월 동안 두 서버에 걸쳐 5건의 개별적인 경로 제한 CVE가 발생했으며, 그 패턴은 여전히 이어지고 있습니다:

  • CVE-2025-53109 / CVE-2025-53110 (filesystem, CVSS 8.4/7.3) — "허용 디렉터리" 검사가 단순한 startsWith() 접두사 매칭을 사용해서, 심볼릭 링크와 단순히 문자열 접두사만 공유하는 형제 디렉터리(예: 허용된 /home/user-safe/home/user-safe-evil에도 매칭)에 의해 우회되어, 파일시스템 전체 읽기/쓰기와 문서화된 RCE 경로를 허용했습니다.

  • CVE-2025-68143 / CVE-2025-68144 / CVE-2025-68145 (git) — git_init이 검증되지 않은 임의의 경로를 허용했고, git_diff/git_checkout가 사용자 제어 인자를 그대로 git CLI에 전달했으며(인자 주입), --repository 제한 모드는 repo_path이 제한된 디렉터리 안에 머무는지 실제로 확인하지 못했습니다.

  • CVE-2026-27735 (git, 이 프로젝트 시작 약 2개월 전에 공개됨) — GitPython의 repo.index.add()로 구현된 git_add../ 형태의 경로에 대해 작업 트리(working tree) 경계를 강제하지 않아, 저장소 밖의 파일을 스테이징하고 빼돌릴 수 있었습니다.

  • 문서화된 RCE 체인: 쓰기 가능한 디렉터리에서 git_init"clean" 필터가 있는 악성 .git/config → 그 필터를 적용하는 .gitattributesgit_add가 필터를 트리거 → 임의의 셸 명령 실행.

이 모든 CVE들은 특정 함수 하나에 문자열/접두사 검사를 하나 더 덧붙이는 방식으로 패치되었습니다. 아무도 이런 경계 강제를 새 도구가 쉽게 빠뜨릴 수 없는 공통 지점으로 옮기지 않았습니다. 그런 결과로 세 번째 CVE가 처음 세 개를 "수정"된 지 정확히 4개월 뒤에 나타났습니다.

Related MCP server: Local Files MCP Server

fsguard-mcp가 다른 점

  1. 모든 곳에서 쓰는 하나의 안전 프리미티브. filesystem이든 git이든 모든 도구는 어떤 작업을 하기 전에 먼저 동일한 ConfinedRoot(confined_path.py 참고)를 통해 대상 경로를 해석합니다. 잊어버릴 수 있는 도구별 경로 검사가 존재하지 않습니다.

  2. 심볼릭 링크 해석 기반, 경로 구성 요소(component) 단위의 containment — 문자열 매칭이 아님. 어떤 경로가 루트 안에 있는지는, 그 경로의 완전히 해석된 실제 경로(모든 심볼릭 링크를 따라간)가 루트 자체의 해석된 실제 경로에 대해 실제로 조상-후손 관계인 하위 경로인 case에만 참입니다. 이 판정은 해석된 경로에 대한 Path.is_relative_to()으로만 수행하며, 문자열에 대한 startsWith()은 절대 사용하지 않습니다. 이 사실만으로 CVE-2025-53109/53110의 정확한 실패 사례가 차단됩니다: 해석된 루트 /allowed에 대해 /allowed-evil은 포함 검사를 통과할 수 없습니다. 경로 구성 요소 비교는 문자열 접두사 비교가 아니기 때문입니다.

  3. 콘텐츠를 위해 git으로 셸을 띄우는 일은 절대 없습니다. git 작업은 dulwich에서 수행됩니다. dulwich은 순수 Python git 구현이라 콘텐츠 관련 작업에 subprocess가 없고 사용자 입력으로 argv를 만들지도 않으며, 특히 clean/smudge 필터를 실행하지 않습니다. 문서화된 RCE 체인이 의존하는 것이 바로 그 기능입니다. 여기에는 인자 주입 표면이 없습니다. 파일 콘텐츠를 읽고 쓰기 위해 외부 프로세스에 건넬 인자 목록 자체가 없기 때문입니다. (단, dulwich은 훅이 존재하면 pre-commit/commit-msg/post-commitsubprocess.call()로 실제 실행하기는 합니다 — 실제 프로세스 실행이지만 콘텐츠 필터링과는 무관합니다. git_commit은 항상 no_verify=True를 전달해 이들을 일단 무시하므로, 그 훅이 실행되지 않기를 우연에 맡기지 않습니다.)

  4. 쓰기 작업은 기존 대상뿐만 아니라 부모 디렉터리도 함께 검증합니다. 이로써 대상이 아직 존재하지 않아서(따라서 "이 경로가 루트 안에 해석되는가"를 존재하지 않는 경로로 확인할 수 없어 심볼릭 해석을 못 하는 케이스) 생기는 버그 계열을 막습니다. 특히 부모 디렉터리 자체가 외부를 가리키는 심볼릭 링크인 경우를 닫습니다. 존재하지 않는 경로 세그먼트는 디스크 상태와 무관하게 어휘 수준에서 ./..를 순수 경로 대수로 정리합니다. 이 모든 것 전에 실행합니다. 이 프로젝트의 초기 버전에서는 정규화를 검사 후에 해만, 결과적으로 테스트가 Windows(경로 API가 ..를 자동으로 정리해줌)에서 전부 통과했지만 Linux/macOS에서 우회 가능 상태였습니다. 지금은 해당 정확한 케이스를 테스트로 고정해두었고요. 다만 그 덕분에 이 프로젝트는 "내 머신에서는 테스트가 초록색"이라는 말에 진지한 의심을 품게 됐습니다.

  5. .git/config로 루트 밖으로 작업을 우회할 수 없습니다. dulwich은 저장소 자체의 core.worktree 설정을 있는대로 따르고, 모든 git 작업이 내부적으로 경로 문자열에서 Repo를 다시 여니까, 호출자가 악성으로 .git/configcore.worktree을 어디에든 가리키게 쓰면, 이후의 git 도구 모두가 제한 루트 밖에서 조용히 작동하게 됩니다. 그리고 경로별 검사(제한된 저장소 디렉터리만 볼 뿐, dulwich이 실제로 자기 자신을 어디로 우회했는지는 볼 수 없음)로 잡혀지지 않습니다. 이번 버그는 첫 커밋 전 두 번째 보안 검토에서 실제 발견됐습니다 — 이 서버가 노출하는 도구만으로 저장소 밖 파일을 읽고 빼돌릴 수 있는, 이서버가 고치려던 어떤 CVE보다 심각한 일이었습니다. 이제 모든 git 도구는 core.worktree 설정이 있는 저장소를 성단 열기를 거부하고, 열었던 Repo 객체가 실제 보고하는 작업 경로가 검증했던 정확한 디렉터리인지도 다시 확인합니다.

  6. UNC 경로와 크로스 드라이브 경로는 네트워크/디스크에 닿기 전에 거부됩니다. \\host\share\... 경로를 해석하면 Windows가 실제로 SMB 연결을 시도합니다. 그리고 그 연결을 서버 프로세스의 자격으로 인증하려 하기 때문에 "UNC 경로를 통한 강제(forced) NTLM auth" 자격 증명 탈취가 발생합니다. 게다가 연결이 불가능한 호스트를 만나면 서버가 전체 커넥션 타임아웃 동안 블로킹됩니다. 허용된 루트와 드라이버, 호스트가 다른 경로는 발생 어떠한 파일시스템/네트워크 작업에 앞서 저렴한 문자열 비교만으로 기각됩니다. NTFS Alternate Data Streams(file.txt:hidden) 역시 원천 차단합니다. 이런 경로는 디렉터리 목록에는 보이지 않지만 동일한 경로 문자열로 충분히 읽기/쓰기가 가능하며, Windows의 다운로드 주의 경고인 "Mark of the Web"이 없는 것처럼 감출 수 있습니다.

Tools

Tools

역할

fs_read(path)

텍스트 파일 읽기

fs_write(path, content)

텍스트 파일 만들기 또는 덮어쓰기

fs_list(path=".")

디렉터리 항목 나열

fs_search(pattern, path=".")

글로브(glob) 일치 파일을 재귀 검색

fs_move(source, destination)

파일 이동/이름 변경

git_init_repo(repo_path)

git 저장소 초기화

git_repo_status(repo_path=".")

스테이지/스테이지되지 않음/추적되지 않음 파일 표시

git_stage(repo_path, paths)

파일을 스테이지

git_commit_repo(repo_path, message, author)

스테이지된 변경사항 커밋

git_diff_repo(repo_path=".", staged=False)

diff 표시

git_log_repo(repo_path=".", max_entries=10)

커밋 이력 표시

Setup

pip install fsguard-mcp
export FSGUARD_ROOT="/path/to/the/one/directory/tree/this/server/may/touch"
fsguard-mcp

FSGUARD_ROOT는 필수입니다. 기본값은 없고, 서버는 하나를 추측하지 않습니다. MCP 클라이언트 설정에서 FSGUARD_ROOT를 지정한 fsguard-mcp 명령어를 가리켜세요.

Testing

pip install -e ".[dev]"
pytest tests/ -v

모든 68개 테스트는 자체적으로 완결되어 있습니다(실제 임시 디렉터리, 실제 심볼릭 링크, 실제 git 저장소가 사용됩니다). 외부 서비스는 필요하지 않습니다.

알려진 제한

포함(containment) 검사를 하고 나서 파일시스템 작업이 수행되는 과정에서, 그 사이에는 내재적으로 TOCTOU(시간-검사-시간-사용, time-of-check-to-time-of-use) 공백이 발생합니다. 제한된 루트의 내부 트리에 대해 쓰기 권한을 가지고 있는 다른 프로세스가 원리를 그 창에 심볼릭 링크를 교체할 수 있습니다(설계 검토 중 실제 동작하는 PoC로 검증한 사항). 완전히 봉인하려면 POSIX 파일시스템 레벨의 프리미티브(리눅스의 openat2(RESOLVE_BENEATH), 혹은 실행되는 mount namespace 자체)가 필요하며, 휴대용(portable) Python으로 해결할 수 있는 범위가 아닙니다. 이 프로젝트가 제공하는 보장은 "사용 직전 시점에 확인하는 올바른 포함 제어 로직"이지, "루트 내부 이미 존재하는 동시성 추구자에게 면역"은 아닙니다.

상태

v0.1.0, PyPI에서 라이브. 테스트 68개 이름(실제 파일시스템에 실제 심볼릭 링크, 실제 git repo 있음. 단순 문자열 논리 검증이 아니라 유닛). 첫 커밋 근처 기준으로 두 차례의 컨테이너 보안 검토를 거쳤고, 두 차례에서 모두 실제로 유효였 던 우회를 찾았습니다(POSIX에서 존재하지 않는 경로 사용한 .. 이동 탈출과 위에서 설명한 core.worktree 재지정, 기타 소소한 발견). 그것들은 현재 수정하여, 발견된 발현형 그대로 씨된 테스트로 보호되며, 새 설치된 pip install에서 배포된 패키지로 재검증했습니다.

License

MIT

Install Server
A
license - permissive license
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables file system operations such as listing, reading, and creating files within a scoped local project directory. It provides a secure way to manage local files through standardized MCP tools built with FastMCP.
  • F
    license
    Not graded
    quality
    C
    maintenance
    Exposes a secure, path-confined bridge to a local workspace and git remotes, enabling MCP clients to search, read, write, reset files, and perform git operations.

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/BerkantACUN/fsguard-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server