Skip to content

Commit be96364

Browse files
committed
add source for react-hook-form in xss-through-dom
1 parent 65d93c9 commit be96364

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,5 +154,21 @@ module XssThroughDom {
154154
)
155155
}
156156
}
157+
158+
/**
159+
* An object containing input values from a form build with `react-hook-form`.
160+
*/
161+
class ReactHookFormSource extends Source {
162+
ReactHookFormSource() {
163+
exists(API::Node useForm |
164+
useForm = API::moduleImport("react-hook-form").getMember("useForm").getReturn()
165+
|
166+
this =
167+
useForm.getMember("handleSubmit").getParameter(0).getParameter(0).getAnImmediateUse()
168+
or
169+
this = useForm.getMember("getValues").getACall()
170+
)
171+
}
172+
}
157173
}
158174
}

javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ nodes
3333
| forms.js:57:19:57:32 | e.target.value |
3434
| forms.js:57:19:57:32 | e.target.value |
3535
| forms.js:57:19:57:32 | e.target.value |
36+
| forms.js:71:21:71:24 | data |
37+
| forms.js:71:21:71:24 | data |
38+
| forms.js:72:19:72:22 | data |
39+
| forms.js:72:19:72:27 | data.name |
40+
| forms.js:72:19:72:27 | data.name |
41+
| forms.js:92:17:92:36 | values |
42+
| forms.js:92:26:92:36 | getValues() |
43+
| forms.js:92:26:92:36 | getValues() |
44+
| forms.js:93:25:93:30 | values |
45+
| forms.js:93:25:93:35 | values.name |
46+
| forms.js:93:25:93:35 | values.name |
3647
| xss-through-dom.js:2:16:2:34 | $("textarea").val() |
3748
| xss-through-dom.js:2:16:2:34 | $("textarea").val() |
3849
| xss-through-dom.js:2:16:2:34 | $("textarea").val() |
@@ -110,6 +121,15 @@ edges
110121
| forms.js:45:21:45:26 | values | forms.js:45:21:45:33 | values.stooge |
111122
| forms.js:45:21:45:26 | values | forms.js:45:21:45:33 | values.stooge |
112123
| forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value |
124+
| forms.js:71:21:71:24 | data | forms.js:72:19:72:22 | data |
125+
| forms.js:71:21:71:24 | data | forms.js:72:19:72:22 | data |
126+
| forms.js:72:19:72:22 | data | forms.js:72:19:72:27 | data.name |
127+
| forms.js:72:19:72:22 | data | forms.js:72:19:72:27 | data.name |
128+
| forms.js:92:17:92:36 | values | forms.js:93:25:93:30 | values |
129+
| forms.js:92:26:92:36 | getValues() | forms.js:92:17:92:36 | values |
130+
| forms.js:92:26:92:36 | getValues() | forms.js:92:17:92:36 | values |
131+
| forms.js:93:25:93:30 | values | forms.js:93:25:93:35 | values.name |
132+
| forms.js:93:25:93:30 | values | forms.js:93:25:93:35 | values.name |
113133
| xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() |
114134
| xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() |
115135
| xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") |
@@ -137,6 +157,8 @@ edges
137157
| forms.js:35:19:35:30 | values.email | forms.js:34:13:34:18 | values | forms.js:35:19:35:30 | values.email | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:34:13:34:18 | values | DOM text |
138158
| forms.js:45:21:45:33 | values.stooge | forms.js:44:21:44:26 | values | forms.js:45:21:45:33 | values.stooge | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:44:21:44:26 | values | DOM text |
139159
| forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:57:19:57:32 | e.target.value | DOM text |
160+
| forms.js:72:19:72:27 | data.name | forms.js:71:21:71:24 | data | forms.js:72:19:72:27 | data.name | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:71:21:71:24 | data | DOM text |
161+
| forms.js:93:25:93:35 | values.name | forms.js:92:26:92:36 | getValues() | forms.js:93:25:93:35 | values.name | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:92:26:92:36 | getValues() | DOM text |
140162
| xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:2:16:2:34 | $("textarea").val() | DOM text |
141163
| xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | DOM text |
142164
| xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | DOM text |

javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,39 @@ const plainReact = () => (
6262
<input type="text" value={this.state.value} onChange={this.handleChange} />
6363
<input type="submit" value="Submit" />
6464
</form>
65-
)
65+
)
66+
67+
import { useForm } from 'react-hook-form';
68+
69+
function HookForm() {
70+
const { register, handleSubmit, errors } = useForm(); // initialize the hook
71+
const onSubmit = (data) => {
72+
$("#id").html(data.name); // NOT OK
73+
};
74+
75+
return (
76+
<form onSubmit={handleSubmit(onSubmit)}>
77+
<input name="name" ref={register({ required: true })} />
78+
<input type="submit" />
79+
</form>
80+
);
81+
}
82+
83+
function HookForm2() {
84+
const { register, getValues } = useForm();
85+
86+
return (
87+
<form>
88+
<input name="name" ref={register} />
89+
<button
90+
type="button"
91+
onClick={() => {
92+
const values = getValues(); // { test: "test-input", test1: "test1-input" }
93+
$("#id").html(values.name); // NOT OK
94+
}}
95+
>
96+
</button>
97+
</form>
98+
);
99+
}
100+

0 commit comments

Comments
 (0)