Skip to content

Commit d84368e

Browse files
authored
Merge pull request #18858 from Napalys/js/react-relay
JS: React-relay support
2 parents 1aa1829 + d077d68 commit d84368e

File tree

5 files changed

+228
-1
lines changed

5 files changed

+228
-1
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added support for the `react-relay` library.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/javascript-all
4+
extensible: sourceModel
5+
data:
6+
- ["react-relay", "Member[useFragment].ReturnValue", "response"]
7+
- ["react-relay", "Member[useLazyLoadQuery].ReturnValue", "response"]
8+
- ["react-relay", "Member[usePreloadedQuery].ReturnValue", "response"]
9+
- ["react-relay", "Member[useClientQuery].ReturnValue", "response"]
10+
- ["react-relay", "Member[useRefetchableFragment].ReturnValue.Member[0]", "response"]
11+
- ["react-relay", "Member[usePaginationFragment].ReturnValue.Member[data]", "response"]
12+
- ["react-relay", "Member[useMutation].ReturnValue.Member[0].Argument[0].Member[onCompleted].Parameter[0]", "response"]
13+
- ["react-relay", "Member[useSubscription].Argument[0].Member[onNext].Parameter[0]", "response"]
14+
- ["react-relay", "Member[fetchQuery].ReturnValue.Member[subscribe].Argument[0].Member[next].Parameter[0]", "response"]
15+
- ["relay-runtime", "Member[readFragment].ReturnValue", "response"]

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

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
#select
22
| test.jsx:27:29:27:32 | data | test.jsx:5:28:5:63 | fetch(" ... ntent") | test.jsx:27:29:27:32 | data | Cross-site scripting vulnerability due to $@. | test.jsx:5:28:5:63 | fetch(" ... ntent") | user-provided value |
3+
| testReactRelay.tsx:7:43:7:58 | commentData.text | testReactRelay.tsx:5:23:5:52 | useFrag ... entRef) | testReactRelay.tsx:7:43:7:58 | commentData.text | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:5:23:5:52 | useFrag ... entRef) | user-provided value |
4+
| testReactRelay.tsx:18:48:18:68 | data.co ... 0].text | testReactRelay.tsx:17:16:17:42 | useLazy ... ry, {}) | testReactRelay.tsx:18:48:18:68 | data.co ... 0].text | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:17:16:17:42 | useLazy ... ry, {}) | user-provided value |
5+
| testReactRelay.tsx:28:17:28:67 | usePrel ... r?.name | testReactRelay.tsx:28:17:28:56 | usePrel ... erence) | testReactRelay.tsx:28:17:28:67 | usePrel ... r?.name | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:28:17:28:56 | usePrel ... erence) | user-provided value |
6+
| testReactRelay.tsx:38:49:38:52 | data | testReactRelay.tsx:37:16:37:40 | useClie ... ry, {}) | testReactRelay.tsx:38:49:38:52 | data | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:37:16:37:40 | useClie ... ry, {}) | user-provided value |
7+
| testReactRelay.tsx:47:46:47:49 | data | testReactRelay.tsx:44:10:44:13 | data | testReactRelay.tsx:47:46:47:49 | data | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:44:10:44:13 | data | user-provided value |
8+
| testReactRelay.tsx:71:49:71:52 | data | testReactRelay.tsx:62:5:62:8 | data | testReactRelay.tsx:71:49:71:52 | data | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:62:5:62:8 | data | user-provided value |
9+
| testReactRelay.tsx:88:50:88:61 | feedbackText | testReactRelay.tsx:83:17:83:20 | data | testReactRelay.tsx:88:50:88:61 | feedbackText | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:83:17:83:20 | data | user-provided value |
10+
| testReactRelay.tsx:113:48:113:58 | fragmentRef | testReactRelay.tsx:100:14:100:16 | res | testReactRelay.tsx:113:48:113:58 | fragmentRef | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:100:14:100:16 | res | user-provided value |
11+
| testReactRelay.tsx:127:35:127:43 | data.user | testReactRelay.tsx:124:12:124:15 | data | testReactRelay.tsx:127:35:127:43 | data.user | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:124:12:124:15 | data | user-provided value |
12+
| testReactRelay.tsx:137:50:137:53 | data | testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | testReactRelay.tsx:137:50:137:53 | data | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | user-provided value |
313
edges
414
| test.jsx:5:11:5:63 | response | test.jsx:6:24:6:31 | response | provenance | |
515
| test.jsx:5:22:5:63 | await f ... ntent") | test.jsx:5:11:5:63 | response | provenance | |
@@ -10,6 +20,31 @@ edges
1020
| test.jsx:6:24:6:38 | response.json() | test.jsx:6:18:6:38 | await r ... .json() | provenance | |
1121
| test.jsx:7:12:7:15 | data | test.jsx:15:11:17:5 | data | provenance | |
1222
| test.jsx:15:11:17:5 | data | test.jsx:27:29:27:32 | data | provenance | |
23+
| testReactRelay.tsx:5:9:5:52 | commentData | testReactRelay.tsx:7:43:7:53 | commentData | provenance | |
24+
| testReactRelay.tsx:5:23:5:52 | useFrag ... entRef) | testReactRelay.tsx:5:9:5:52 | commentData | provenance | |
25+
| testReactRelay.tsx:7:43:7:53 | commentData | testReactRelay.tsx:7:43:7:58 | commentData.text | provenance | |
26+
| testReactRelay.tsx:17:9:17:42 | data | testReactRelay.tsx:18:48:18:51 | data | provenance | |
27+
| testReactRelay.tsx:17:16:17:42 | useLazy ... ry, {}) | testReactRelay.tsx:17:9:17:42 | data | provenance | |
28+
| testReactRelay.tsx:18:48:18:51 | data | testReactRelay.tsx:18:48:18:68 | data.co ... 0].text | provenance | |
29+
| testReactRelay.tsx:28:17:28:56 | usePrel ... erence) | testReactRelay.tsx:28:17:28:67 | usePrel ... r?.name | provenance | |
30+
| testReactRelay.tsx:37:9:37:40 | data | testReactRelay.tsx:38:49:38:52 | data | provenance | |
31+
| testReactRelay.tsx:37:16:37:40 | useClie ... ry, {}) | testReactRelay.tsx:37:9:37:40 | data | provenance | |
32+
| testReactRelay.tsx:44:9:44:70 | data | testReactRelay.tsx:47:46:47:49 | data | provenance | |
33+
| testReactRelay.tsx:44:10:44:13 | data | testReactRelay.tsx:44:9:44:70 | data | provenance | |
34+
| testReactRelay.tsx:61:9:70:38 | data | testReactRelay.tsx:71:49:71:52 | data | provenance | |
35+
| testReactRelay.tsx:62:5:62:8 | data | testReactRelay.tsx:61:9:70:38 | data | provenance | |
36+
| testReactRelay.tsx:80:9:80:54 | feedbackText | testReactRelay.tsx:88:50:88:61 | feedbackText | provenance | |
37+
| testReactRelay.tsx:80:10:80:21 | feedbackText | testReactRelay.tsx:80:9:80:54 | feedbackText | provenance | |
38+
| testReactRelay.tsx:83:17:83:20 | data | testReactRelay.tsx:84:23:84:26 | data | provenance | |
39+
| testReactRelay.tsx:84:23:84:26 | data | testReactRelay.tsx:80:10:80:21 | feedbackText | provenance | |
40+
| testReactRelay.tsx:95:9:95:50 | fragmentRef | testReactRelay.tsx:113:48:113:58 | fragmentRef | provenance | |
41+
| testReactRelay.tsx:95:10:95:20 | fragmentRef | testReactRelay.tsx:95:9:95:50 | fragmentRef | provenance | |
42+
| testReactRelay.tsx:100:14:100:16 | res | testReactRelay.tsx:101:22:101:24 | res | provenance | |
43+
| testReactRelay.tsx:101:22:101:24 | res | testReactRelay.tsx:95:10:95:20 | fragmentRef | provenance | |
44+
| testReactRelay.tsx:124:12:124:15 | data | testReactRelay.tsx:127:35:127:38 | data | provenance | |
45+
| testReactRelay.tsx:127:35:127:38 | data | testReactRelay.tsx:127:35:127:43 | data.user | provenance | |
46+
| testReactRelay.tsx:136:9:136:39 | data | testReactRelay.tsx:137:50:137:53 | data | provenance | |
47+
| testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | testReactRelay.tsx:136:9:136:39 | data | provenance | |
1348
nodes
1449
| test.jsx:5:11:5:63 | response | semmle.label | response |
1550
| test.jsx:5:22:5:63 | await f ... ntent") | semmle.label | await f ... ntent") |
@@ -21,4 +56,39 @@ nodes
2156
| test.jsx:7:12:7:15 | data | semmle.label | data |
2257
| test.jsx:15:11:17:5 | data | semmle.label | data |
2358
| test.jsx:27:29:27:32 | data | semmle.label | data |
59+
| testReactRelay.tsx:5:9:5:52 | commentData | semmle.label | commentData |
60+
| testReactRelay.tsx:5:23:5:52 | useFrag ... entRef) | semmle.label | useFrag ... entRef) |
61+
| testReactRelay.tsx:7:43:7:53 | commentData | semmle.label | commentData |
62+
| testReactRelay.tsx:7:43:7:58 | commentData.text | semmle.label | commentData.text |
63+
| testReactRelay.tsx:17:9:17:42 | data | semmle.label | data |
64+
| testReactRelay.tsx:17:16:17:42 | useLazy ... ry, {}) | semmle.label | useLazy ... ry, {}) |
65+
| testReactRelay.tsx:18:48:18:51 | data | semmle.label | data |
66+
| testReactRelay.tsx:18:48:18:68 | data.co ... 0].text | semmle.label | data.co ... 0].text |
67+
| testReactRelay.tsx:28:17:28:56 | usePrel ... erence) | semmle.label | usePrel ... erence) |
68+
| testReactRelay.tsx:28:17:28:67 | usePrel ... r?.name | semmle.label | usePrel ... r?.name |
69+
| testReactRelay.tsx:37:9:37:40 | data | semmle.label | data |
70+
| testReactRelay.tsx:37:16:37:40 | useClie ... ry, {}) | semmle.label | useClie ... ry, {}) |
71+
| testReactRelay.tsx:38:49:38:52 | data | semmle.label | data |
72+
| testReactRelay.tsx:44:9:44:70 | data | semmle.label | data |
73+
| testReactRelay.tsx:44:10:44:13 | data | semmle.label | data |
74+
| testReactRelay.tsx:47:46:47:49 | data | semmle.label | data |
75+
| testReactRelay.tsx:61:9:70:38 | data | semmle.label | data |
76+
| testReactRelay.tsx:62:5:62:8 | data | semmle.label | data |
77+
| testReactRelay.tsx:71:49:71:52 | data | semmle.label | data |
78+
| testReactRelay.tsx:80:9:80:54 | feedbackText | semmle.label | feedbackText |
79+
| testReactRelay.tsx:80:10:80:21 | feedbackText | semmle.label | feedbackText |
80+
| testReactRelay.tsx:83:17:83:20 | data | semmle.label | data |
81+
| testReactRelay.tsx:84:23:84:26 | data | semmle.label | data |
82+
| testReactRelay.tsx:88:50:88:61 | feedbackText | semmle.label | feedbackText |
83+
| testReactRelay.tsx:95:9:95:50 | fragmentRef | semmle.label | fragmentRef |
84+
| testReactRelay.tsx:95:10:95:20 | fragmentRef | semmle.label | fragmentRef |
85+
| testReactRelay.tsx:100:14:100:16 | res | semmle.label | res |
86+
| testReactRelay.tsx:101:22:101:24 | res | semmle.label | res |
87+
| testReactRelay.tsx:113:48:113:58 | fragmentRef | semmle.label | fragmentRef |
88+
| testReactRelay.tsx:124:12:124:15 | data | semmle.label | data |
89+
| testReactRelay.tsx:127:35:127:38 | data | semmle.label | data |
90+
| testReactRelay.tsx:127:35:127:43 | data.user | semmle.label | data.user |
91+
| testReactRelay.tsx:136:9:136:39 | data | semmle.label | data |
92+
| testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | semmle.label | readFra ... y, key) |
93+
| testReactRelay.tsx:137:50:137:53 | data | semmle.label | data |
2494
subpaths
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import React, { useState } from "react";
2+
import { useFragment } from 'react-relay';
3+
4+
const func1 = ({ commentRef, query }) => {
5+
const commentData = useFragment(query, commentRef); // $ Source=[js/xss]
6+
return (
7+
<p dangerouslySetInnerHTML={{ __html: commentData.text }}> // $ Alert=[js/xss]
8+
{" "}
9+
{commentData.text}
10+
</p>
11+
);
12+
};
13+
14+
import { useLazyLoadQuery } from "react-relay";
15+
16+
function func2({ query }) {
17+
const data = useLazyLoadQuery(query, {}); // $ Source
18+
return <p dangerouslySetInnerHTML={{ __html: data.comments[0].text }} />; // $ Alert
19+
}
20+
21+
import { useQueryLoader, usePreloadedQuery } from "react-relay";
22+
23+
function func3({ initialQueryRef, query }) {
24+
const [queryReference, loadQuery] = useQueryLoader(query, initialQueryRef);
25+
return (
26+
<h1
27+
dangerouslySetInnerHTML={{
28+
__html: usePreloadedQuery(query, queryReference).user?.name, // $ Alert
29+
}}
30+
/>
31+
);
32+
}
33+
34+
import { useClientQuery } from "react-relay";
35+
36+
function func4({ query }) {
37+
const data = useClientQuery(query, {}); // $ Source
38+
return <h1 dangerouslySetInnerHTML={{ __html: data }} />; // $ Alert
39+
}
40+
41+
import { useRefetchableFragment } from "react-relay";
42+
43+
function func5({ query, props }) {
44+
const [data, refetch] = useRefetchableFragment(query, props.comment); // $ Source
45+
return (
46+
<>
47+
<h1 dangerouslySetInnerHTML={{ __html: data }} /> // $ Alert
48+
<h1 dangerouslySetInnerHTML={{ __html: refetch }} />
49+
<Button
50+
onClick={() => {
51+
refetch({ lang: "SPANISH" }, { fetchPolicy: "store-or-network" });
52+
}}
53+
></Button>
54+
</>
55+
);
56+
}
57+
58+
import { usePaginationFragment } from "react-relay";
59+
60+
function func6({ query }) {
61+
const {
62+
data, // $ Source
63+
loadNext,
64+
loadPrevious,
65+
hasNext,
66+
hasPrevious,
67+
isLoadingNext,
68+
isLoadingPrevious,
69+
refetch,
70+
} = usePaginationFragment(query, {});
71+
return <h1 dangerouslySetInnerHTML={{ __html: data }} />; // $ Alert
72+
}
73+
74+
75+
import { useMutation } from 'react-relay';
76+
import type { FeedbackLikeMutation } from './FeedbackLikeMutation.graphql';
77+
78+
function func7(query) {
79+
const [commit, inFlight] = useMutation<FeedbackLikeMutation>(query);
80+
const [feedbackText, setFeedbackText] = useState('');
81+
82+
commit({
83+
onCompleted(data) { // $ Source
84+
setFeedbackText(data);
85+
},
86+
});
87+
88+
return (<div dangerouslySetInnerHTML={{__html: feedbackText, }}/>); // $ Alert
89+
}
90+
91+
import { useSubscription } from 'react-relay';
92+
import { useMemo } from 'react';
93+
94+
function func8({GroupLessonsSubscription}) {
95+
const [fragmentRef, setFragmentRef] = useState();
96+
97+
const groupLessonConfig = useMemo(() => ({
98+
subscription: GroupLessonsSubscription,
99+
variables: {},
100+
onNext: (res) => { // $ Source
101+
setFragmentRef(res);
102+
},
103+
onError: (err) => {
104+
console.error('Error with subscription:', err);
105+
},
106+
onCompleted: () => {
107+
console.log('Subscription completed');
108+
},
109+
}), []);
110+
111+
useSubscription(groupLessonConfig);
112+
113+
return (<div dangerouslySetInnerHTML={{__html: fragmentRef, }}/>); // $ Alert
114+
}
115+
116+
117+
import { fetchQuery } from 'react-relay'
118+
119+
function func9({query, environment}) {
120+
fetchQuery(environment, query,{id: 4},).subscribe({
121+
start: () => {},
122+
complete: () => {},
123+
error: (error) => {},
124+
next: (data) => { // $ Source
125+
const outputElement = document.getElementById('output');
126+
if (outputElement) {
127+
outputElement.innerHTML = data.user; // $ Alert
128+
}
129+
}
130+
});
131+
}
132+
133+
import { readFragment } from "relay-runtime";
134+
135+
function func10({ query, key }) {
136+
const data = readFragment(query, key); // $ Source
137+
return (<h1 dangerouslySetInnerHTML={{ __html: data }} />); // $ Alert
138+
}

shared/mad/codeql/mad/ModelValidation.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ module KindValidation<KindValidationConfigSig Config> {
125125
// C#
126126
"file-write", "windows-registry",
127127
// JavaScript
128-
"database-access-result"
128+
"database-access-result", "response", "request"
129129
]
130130
or
131131
this.matches([

0 commit comments

Comments
 (0)