Skip to content

Commit 96896fd

Browse files
committed
second round of UnsafeJQueryPlugin reuse
1 parent ea569db commit 96896fd

File tree

3 files changed

+48
-60
lines changed

3 files changed

+48
-60
lines changed

javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import semmle.javascript.security.dataflow.UnsafeJQueryPlugin::UnsafeJQueryPlugi
1616
import DataFlow::PathGraph
1717

1818
from
19-
Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, JQueryPluginMethod plugin
19+
Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, JQuery::JQueryPluginMethod plugin
2020
where
2121
cfg.hasFlowPath(source, sink) and
2222
source.getNode().(Source).getPlugin() = plugin and

javascript/ql/src/semmle/javascript/frameworks/jQuery.qll

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -497,24 +497,12 @@ module JQuery {
497497
}
498498
}
499499

500-
/**
501-
* Gets a node that is backtracked from a node written to `$.fn[something]`.
502-
*/
503-
private DataFlow::SourceNode writtenToJqueryFN(DataFlow::TypeBackTracker t) {
504-
t.start() and result = any(DataFlow::Node plugin | jQueryPluginDefinition(_, plugin)).getALocalSource()
505-
or
506-
exists(DataFlow::TypeBackTracker t2 | result = writtenToJqueryFN(t2).backtrack(t2, t))
507-
}
508-
509500
/**
510501
* A `this` node in a JQuery plugin function, which is a JQuery object.
511502
*/
512503
private class JQueryPluginThisObject extends Range {
513504
JQueryPluginThisObject() {
514-
this =
515-
DataFlow::thisNode(writtenToJqueryFN(DataFlow::TypeBackTracker::end())
516-
.(DataFlow::FunctionNode)
517-
.getFunction())
505+
this = DataFlow::thisNode(any(JQueryPluginMethod method).getFunction())
518506
}
519507
}
520508
}
@@ -615,7 +603,7 @@ module JQuery {
615603
/**
616604
* Holds for jQuery plugin definitions of the form `$.fn.<pluginName> = <plugin>` or $.extend($.fn, {<pluginName>, <plugin>})`.
617605
*/
618-
predicate jQueryPluginDefinition(string pluginName, DataFlow::Node plugin) {
606+
private predicate jQueryPluginDefinition(string pluginName, DataFlow::Node plugin) {
619607
exists(DataFlow::PropRead fn, DataFlow::PropWrite write |
620608
fn = jquery().getAPropertyRead("fn") and
621609
(
@@ -634,4 +622,41 @@ module JQuery {
634622
)
635623
)
636624
}
625+
626+
/**
627+
* Gets a node that is registered as a jQuery plugin method at `def`.
628+
*/
629+
private DataFlow::SourceNode getAJQueryPluginMethod(
630+
DataFlow::TypeBackTracker t, DataFlow::Node def
631+
) {
632+
t.start() and jQueryPluginDefinition(_, def) and result.flowsTo(def)
633+
or
634+
exists(DataFlow::TypeBackTracker t2 | result = getAJQueryPluginMethod(t2, def).backtrack(t2, t))
635+
}
636+
637+
/**
638+
* Gets a function that is registered as a jQuery plugin method at `def`.
639+
*/
640+
private DataFlow::FunctionNode getAJQueryPluginMethod(DataFlow::Node def) {
641+
result = getAJQueryPluginMethod(DataFlow::TypeBackTracker::end(), def)
642+
}
643+
644+
/**
645+
* A function that is registered as a jQuery plugin method.
646+
*/
647+
class JQueryPluginMethod extends DataFlow::FunctionNode {
648+
string pluginName;
649+
650+
JQueryPluginMethod() {
651+
exists(DataFlow::Node def |
652+
jQueryPluginDefinition(pluginName, def) and
653+
this = getAJQueryPluginMethod(def)
654+
)
655+
}
656+
657+
/**
658+
* Gets the name of this plugin.
659+
*/
660+
string getPluginName() { result = pluginName }
661+
}
637662
}

javascript/ql/src/semmle/javascript/security/dataflow/UnsafeJQueryPluginCustomizations.qll

Lines changed: 8 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ module UnsafeJQueryPlugin {
1818
/**
1919
* Gets the plugin that this source is used in.
2020
*/
21-
abstract JQueryPluginMethod getPlugin();
21+
abstract JQuery::JQueryPluginMethod getPlugin();
2222
}
2323

2424
/**
@@ -49,26 +49,6 @@ module UnsafeJQueryPlugin {
4949
}
5050
}
5151

52-
/**
53-
* Gets a node that is registered as a jQuery plugin method at `def`.
54-
*/
55-
private DataFlow::SourceNode getAJQueryPluginMethod(
56-
DataFlow::TypeBackTracker t, DataFlow::Node def
57-
) {
58-
t.start() and
59-
jQueryPluginDefinition(_, def) and
60-
result.flowsTo(def)
61-
or
62-
exists(DataFlow::TypeBackTracker t2 | result = getAJQueryPluginMethod(t2, def).backtrack(t2, t))
63-
}
64-
65-
/**
66-
* Gets a function that is registered as a jQuery plugin method at `def`.
67-
*/
68-
private DataFlow::FunctionNode getAJQueryPluginMethod(DataFlow::Node def) {
69-
result = getAJQueryPluginMethod(DataFlow::TypeBackTracker::end(), def)
70-
}
71-
7252
/**
7353
* Gets an operand to `extend`.
7454
*/
@@ -86,29 +66,10 @@ module UnsafeJQueryPlugin {
8666
result = getAnExtendOperand(DataFlow::TypeBackTracker::end(), extend)
8767
}
8868

89-
/**
90-
* A function that is registered as a jQuery plugin method.
91-
*/
92-
class JQueryPluginMethod extends DataFlow::FunctionNode {
93-
string pluginName;
94-
95-
JQueryPluginMethod() {
96-
exists(DataFlow::Node def |
97-
jQueryPluginDefinition(pluginName, def) and
98-
this = getAJQueryPluginMethod(def)
99-
)
100-
}
101-
102-
/**
103-
* Gets the name of this plugin.
104-
*/
105-
string getPluginName() { result = pluginName }
106-
}
107-
10869
/**
10970
* Holds if `plugin` has a default option defined at `def`.
11071
*/
111-
private predicate hasDefaultOption(JQueryPluginMethod plugin, DataFlow::PropWrite def) {
72+
private predicate hasDefaultOption(JQuery::JQueryPluginMethod plugin, DataFlow::PropWrite def) {
11273
exists(ExtendCall extend, JQueryPluginOptions options, DataFlow::SourceNode default |
11374
options.getPlugin() = plugin and
11475
options = getAnExtendOperand(extend) and
@@ -121,7 +82,7 @@ module UnsafeJQueryPlugin {
12182
* The client-provided options object for a jQuery plugin.
12283
*/
12384
class JQueryPluginOptions extends DataFlow::ParameterNode {
124-
JQueryPluginMethod method;
85+
JQuery::JQueryPluginMethod method;
12586

12687
JQueryPluginOptions() {
12788
exists(string optionsPattern |
@@ -142,7 +103,7 @@ module UnsafeJQueryPlugin {
142103
/**
143104
* Gets the plugin method that these options are used in.
144105
*/
145-
JQueryPluginMethod getPlugin() { result = method }
106+
JQuery::JQueryPluginMethod getPlugin() { result = method }
146107
}
147108

148109
/**
@@ -201,7 +162,9 @@ module UnsafeJQueryPlugin {
201162
* The client-provided options object for a jQuery plugin, considered as a source for unsafe jQuery plugins.
202163
*/
203164
class JQueryPluginOptionsAsSource extends Source, JQueryPluginOptions {
204-
override JQueryPluginMethod getPlugin() { result = JQueryPluginOptions.super.getPlugin() }
165+
override JQuery::JQueryPluginMethod getPlugin() {
166+
result = JQueryPluginOptions.super.getPlugin()
167+
}
205168
}
206169

207170
/**
@@ -223,7 +186,7 @@ module UnsafeJQueryPlugin {
223186
/**
224187
* Holds if `plugin` likely expects `sink` to be treated as a HTML fragment.
225188
*/
226-
predicate isLikelyIntentionalHtmlSink(JQueryPluginMethod plugin, Sink sink) {
189+
predicate isLikelyIntentionalHtmlSink(JQuery::JQueryPluginMethod plugin, Sink sink) {
227190
exists(DataFlow::PropWrite defaultDef, string default, DataFlow::PropRead finalRead |
228191
hasDefaultOption(plugin, defaultDef) and
229192
defaultDef.getPropertyName() = finalRead.getPropertyName() and

0 commit comments

Comments
 (0)