-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathCVE-2025-32959-query.ql
More file actions
119 lines (109 loc) · 4.72 KB
/
Copy pathCVE-2025-32959-query.ql
File metadata and controls
119 lines (109 loc) · 4.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* @name Unrestricted file upload leading to resource exhaustion (CVE-2025-32959)
* @description File upload operations without size limits can lead to resource exhaustion attacks
* @problem.severity error
* @security-severity 7.5
* @precision high
* @tags security
* @kind path-problem
* @id cuba-unrestricted-file-upload
*/
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.dataflow.ExternalFlow
class FileUploadSource extends DataFlow::Node {
FileUploadSource() {
// Specifically target the InputStream parameter in FileStorage.saveStream method
exists(Method saveStreamMethod, Parameter inputStreamParam |
saveStreamMethod.getDeclaringType().hasName("FileStorage") and
saveStreamMethod.hasName("saveStream") and
inputStreamParam = saveStreamMethod.getAParameter() and
inputStreamParam.getType().hasName("InputStream") and
this.asParameter() = inputStreamParam
)
or
// Also include any usage of that parameter within the method
exists(Method saveStreamMethod, Parameter inputStreamParam |
saveStreamMethod.getDeclaringType().hasName("FileStorage") and
saveStreamMethod.hasName("saveStream") and
inputStreamParam = saveStreamMethod.getAParameter() and
inputStreamParam.getType().hasName("InputStream") and
this.asExpr() = inputStreamParam.getAnAccess()
)
}
}
class UnrestrictedFileCopySink extends DataFlow::Node {
UnrestrictedFileCopySink() {
// Sink: IOUtils.copyLarge with 2 arguments (no size limit) inside FileStorage.saveStream
exists(MethodCall copyCall, Method containingMethod |
copyCall.getMethod().hasName("copyLarge") and
copyCall.getMethod().getDeclaringType().hasName("IOUtils") and
copyCall.getNumArgument() = 2 and
containingMethod = copyCall.getEnclosingCallable() and
containingMethod.getDeclaringType().hasName("FileStorage") and
containingMethod.hasName("saveStream") and
this.asExpr() = copyCall
)
or
// Alternative: IOUtils.copy with 2 arguments (no size limit)
exists(MethodCall copyCall, Method containingMethod |
copyCall.getMethod().hasName("copy") and
copyCall.getMethod().getDeclaringType().hasName("IOUtils") and
copyCall.getNumArgument() = 2 and
containingMethod = copyCall.getEnclosingCallable() and
containingMethod.getDeclaringType().hasName("FileStorage") and
containingMethod.hasName("saveStream") and
this.asExpr() = copyCall
)
or
// Also catch the InputStream argument to these calls
exists(MethodCall copyCall, Method containingMethod |
(copyCall.getMethod().hasName("copyLarge") or copyCall.getMethod().hasName("copy")) and
copyCall.getMethod().getDeclaringType().hasName("IOUtils") and
copyCall.getNumArgument() = 2 and
containingMethod = copyCall.getEnclosingCallable() and
containingMethod.getDeclaringType().hasName("FileStorage") and
containingMethod.hasName("saveStream") and
this.asExpr() = copyCall.getArgument(0)
)
}
}
class FileSizeLimitSanitizer extends DataFlow::Node {
FileSizeLimitSanitizer() {
// Sanitizer: IOUtils.copyLarge with size limit (4+ arguments)
exists(MethodCall copyCall |
copyCall.getMethod().hasName("copyLarge") and
copyCall.getMethod().getDeclaringType().hasName("IOUtils") and
copyCall.getNumArgument() >= 4 and
this.asExpr() = copyCall
)
or
// Configuration-based file size limits
exists(MethodCall configCall |
configCall.getMethod().hasName("getFileStorageMaxFileSize") and
this.asExpr() = configCall
)
or
// Size validation checks or limits
exists(Variable sizeVar |
(sizeVar.getName().toLowerCase().matches("%max%") or
sizeVar.getName().toLowerCase().matches("%limit%") or
sizeVar.getName().toLowerCase().matches("%size%")) and
this.asExpr() = sizeVar.getAnAccess()
)
}
}
module FileUploadConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof FileUploadSource }
predicate isSink(DataFlow::Node sink) { sink instanceof UnrestrictedFileCopySink }
predicate isBarrier(DataFlow::Node sanitizer) { sanitizer instanceof FileSizeLimitSanitizer }
}
module FileUploadFlow = TaintTracking::Global<FileUploadConfig>;
import FileUploadFlow::PathGraph
from FileUploadFlow::PathNode source, FileUploadFlow::PathNode sink
where FileUploadFlow::flowPath(source, sink)
select sink.getNode(), source, sink,
"Unrestricted file upload operation allows potential resource exhaustion via large file uploads in FileStorage.saveStream",
source.getNode(), "File upload source in saveStream method"