Skip to content

Commit 7ff8a2b

Browse files
author
Bruce Hauman
committed
Restrict deps_read jar paths to dependency cache directories
Validate that jar paths passed to deps_read are under ~/.m2/repository or ~/.clojure-mcp/deps_cache to prevent reading arbitrary jar files via path traversal.
1 parent 09a4332 commit 7ff8a2b

2 files changed

Lines changed: 52 additions & 1 deletion

File tree

src/clojure_mcp/tools/deps_read/core.clj

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
[clojure.string :as str]
55
[clojure.java.io :as io]
66
[clojure-mcp.tools.deps-common.jar-utils :as jar-utils]
7-
[taoensso.timbre :as log]))
7+
[clojure-mcp.utils.valid-paths :as valid-paths]
8+
[taoensso.timbre :as log])
9+
(:import
10+
(java.io File)))
811

912
(defn list-jar-entries
1013
"List all entries in a jar file.
@@ -95,6 +98,21 @@
9598
{:jar-path jar-path
9699
:entry-path entry-path})))))
97100

101+
(defn allowed-jar-dirs
102+
"Returns the list of directories that jar paths are allowed to reside in.
103+
- ~/.m2/repository (Maven local cache)
104+
- ~/.clojure-mcp/deps_cache (downloaded sources cache)"
105+
[]
106+
(let [home (System/getProperty "user.home")]
107+
[(.getPath (io/file home ".m2" "repository"))
108+
(.getPath (io/file home ".clojure-mcp" "deps_cache"))]))
109+
110+
(defn validate-jar-path!
111+
"Validates that a jar path is under an allowed dependency cache directory.
112+
Returns the normalized path if valid, throws ex-info if not."
113+
[jar-path]
114+
(valid-paths/validate-path jar-path "/" (allowed-jar-dirs)))
115+
98116
(defn deps-read
99117
"Read a file from a dependency jar.
100118
@@ -112,6 +130,7 @@
112130
(deps-read jar-path entry-path opts)
113131
{:error (str "Invalid path format. Expected 'jar-path:entry-path', got: " path)}))
114132
([jar-path entry-path opts]
133+
(validate-jar-path! jar-path)
115134
(read-jar-entry jar-path entry-path
116135
:offset (or (:offset opts) 0)
117136
:limit (:limit opts)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
(ns clojure-mcp.tools.deps-read.core-test
2+
(:require [clojure.test :refer [deftest is testing]]
3+
[clojure-mcp.tools.deps-read.core :as sut]
4+
[clojure.java.io :as io]))
5+
6+
(deftest validate-jar-path-test
7+
(let [home (System/getProperty "user.home")
8+
m2-jar (str home "/.m2/repository/org/clojure/clojure/1.11.1/clojure-1.11.1.jar")
9+
cache-jar (str home "/.clojure-mcp/deps_cache/org/clojure/clojure-1.11.1-sources.jar")]
10+
11+
(testing "accepts paths under ~/.m2/repository"
12+
(is (string? (sut/validate-jar-path! m2-jar))))
13+
14+
(testing "accepts paths under ~/.clojure-mcp/deps_cache"
15+
(is (string? (sut/validate-jar-path! cache-jar))))
16+
17+
(testing "rejects paths outside allowed directories"
18+
(is (thrown? clojure.lang.ExceptionInfo
19+
(sut/validate-jar-path! "/tmp/evil.jar"))))
20+
21+
(testing "rejects path traversal attacks"
22+
(is (thrown? clojure.lang.ExceptionInfo
23+
(sut/validate-jar-path!
24+
(str home "/.m2/repository/../../etc/foo.jar")))))))
25+
26+
(deftest allowed-jar-dirs-test
27+
(testing "returns expected directories"
28+
(let [home (System/getProperty "user.home")
29+
dirs (sut/allowed-jar-dirs)]
30+
(is (= 2 (count dirs)))
31+
(is (some #(.contains % ".m2/repository") dirs))
32+
(is (some #(.contains % ".clojure-mcp/deps_cache") dirs)))))

0 commit comments

Comments
 (0)