SparkJava文件符号链接穿越CVE-2026-17459
SparkJava 是轻量级 Java 微 Web 框架,灵感源自 Ruby Sinatra,主打极简快速开发 REST 接口、小型网页,内置嵌入式 Jetty 服务。
一、基本情况
SparkJava 适用场景一般是小型后台接口、内部工具服务、爬虫配套 API、轻量演示站点、本地测试服务;不适合大型复杂企业系统。

SparkJava 轻量化,原生支持 GET/POST/PUT/DELETE 全部 HTTP 方法,支持路径参数、过滤器、全局拦截器,快速搭建 API 接口。
栋科技漏洞库关注到SparkJava 外部静态文件符号链接穿越漏洞,该漏洞现在已经被追踪为CVE-2026-17459,漏洞CVSS 3.X评分 4.3。
二、漏洞分析
CVE-2026-17459漏洞是 SparkJava 外部静态文件符号链接绕过漏洞,可读取静态根目录以外本地文件,影响外部静态文件处理模块。
SparkJava 是一个开源的 Java Web 微框架,通过 staticFiles.externalLocation 提供外部目录的静态文件服务。
外部静态文件处理器通过对请求路径做字符串前缀校验,限制访问范围不超出静态根目录,但打开文件前并未解析文件真实物理路径。
这意味着若配置的外部静态目录内存在符号链接,且该链接指向目录外部文件,SparkJava 会跟随符号链接并对外返回目标文件内容。
具体来说,受影响版本中,当用户请求的路径在外部静态根目录下以符号链接形式指向根目录之外的文件时,
ExternalResourceHandler.getResource 仅基于规范化后的字符串前缀执行 DirectoryTraversal.protectAgainstForExternal 检查,
未调用 toRealPath 或其它符号链接解析手段,而 ExternalResource.getInputStream 通过 FileInputStream 直接打开文件,
文件系统会透明地跟随符号链接到外部文件,从而绕过静态根目录边界,造成 Java 进程可读任意本地文件被以 HTTP 响应形式泄露;
外部攻击者可借助受影响应用对外暴露的 staticFiles.externalLocation 接口发起远程读取。
该缺陷影响 com.sparkjava:spark-core 通过 staticFiles.externalLocation 暴露外部目录的所有部署,覆盖 2.9.4 及之前所有已发布版本。
1、 漏洞影响
攻击者若能在 staticFiles.externalLocation(...)`所配置的静态目录内创建或操控符号链接,
即可利用该漏洞读取 Java 进程拥有读取权限的服务器任意本地文件。
常见高危业务场景:程序将用户上传解压压缩包、构建产物、自动生成文档、上传文件夹作为外部静态资源对外提供访问。
并非所有部署 SparkJava 静态资源的应用都可远程利用;
漏洞利用的前提是攻击者可控的符号链接(或等同文件系统环境)存在于配置的外部静态根目录内。
2、源码佐证
外部资源处理器会规范化 HTTP 请求路径,并将其与配置的外部静态根目录拼接。
src/main/java/spark/resource/ExternalResourceHandler.java:66
src/main/java/spark/resource/ExternalResourceHandler.java:68
src/main/java/spark/resource/ExternalResourceHandler.java:70
path = UriPath.canonical(path);
final String addedPath = addPaths(baseResource, path);
ExternalResource resource = new ExternalResource(addedPath);
在返回资源之前,该代码会执行目录遍历防护校验逻辑:
src/main/java/spark/resource/ExternalResourceHandler.java:81
src/main/java/spark/resource/ExternalResourceHandler.java:82
if (resource != null && resource.exists()) {
DirectoryTraversal.protectAgainstForExternal(resource.getPath(), baseResource);
return resource;
}
该防护机制仅对比标准化后的字符串,未调用 toRealPath ()、getCanonicalFile (),也不会拦截符号链接:
src/main/java/spark/staticfiles/DirectoryTraversal.java:18
src/main/java/spark/staticfiles/DirectoryTraversal.java:26
src/main/java/spark/staticfiles/DirectoryTraversal.java:30
src/main/java/spark/staticfiles/DirectoryTraversal.java:33
public static void protectAgainstForExternal(String path, String externalFolder) {
String unixLikeFolder = unixifyPath(externalFolder);
String nixLikePath = unixifyPath(path);
if (!isPathWithinFolder(nixLikePath, unixLikeFolder)) {
throw new DirectoryTraversalDetection("external");
}
}
private static String unixifyPath(String path) {
return Paths.get(path).toAbsolutePath().toString().replace("\\", "/");
}
private static boolean isPathWithinFolder(String path, String folder) {
String rlatsPath = removeLeadingAndTrailingSlashesFrom(path);
String rlatsFolder = removeLeadingAndTrailingSlashesFrom(folder);
return rlatsPath.startsWith(rlatsFolder);
}
随后 ExternalResource 使用 FileInputStream 打开文件路径,在常规文件系统中该类会自动跟随符号链接:
src/main/java/spark/resource/ExternalResource.java:39
src/main/java/spark/resource/ExternalResource.java:66
file = new File(StringUtils.cleanPath(path));
public InputStream getInputStream() throws IOException {
return new FileInputStream(file);
}
三、POC概念验证
(一)本地复现步骤
1、本地编写了如下 JUnit 概念验证代码:
管理员已设置登录后刷新可查看2、运行
cd C:\Users\Admin\Desktop\submit-p\_foreign_cve_repos\spark
mvn -q "-Dtest=spark.staticfiles.StaticFilesSymlinkEscapeTest" "-Denforcer.skip=true" test
3、观测结果
Tests run successfully


(二)测试创建以下内容:
1、一个外部静态资源根目录;
2、一个独立的外部目录,目录内存在 secret.txt 机密文件;
3、在静态根目录中创建名为 link.txt 的符号链接,指向 secret.txt;
4、发起等效于访问 /link.txt 的请求。
SparkJava 会返回可读资源,文件内容包含文本 spark-symlink-escape,证明攻击者可借助符号链接突破静态根目录访问限制。
四、影响范围
SparkJava ≤2.9.4-SNAPSHOT、2.9.3
五、修复建议
SparkJava >2.9.4-SNAPSHOT、2.9.3
六、参考链接
管理员已设置登录后刷新可查看