From 9534188f1f27eda25506371a86be0e98ad8d4d82 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Tue, 21 Oct 2025 17:16:39 -0400 Subject: [PATCH 1/5] Add react precallgraphstep useRef --- .../2025-10-21-react-precallgraph-step.md | 4 ++++ .../semmle/javascript/frameworks/React.qll | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2025-10-21-react-precallgraph-step.md diff --git a/javascript/ql/lib/change-notes/2025-10-21-react-precallgraph-step.md b/javascript/ql/lib/change-notes/2025-10-21-react-precallgraph-step.md new file mode 100644 index 000000000000..efba56b34707 --- /dev/null +++ b/javascript/ql/lib/change-notes/2025-10-21-react-precallgraph-step.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added PreCallGraphStep flow model for React's `useRef` hook. \ No newline at end of file diff --git a/javascript/ql/lib/semmle/javascript/frameworks/React.qll b/javascript/ql/lib/semmle/javascript/frameworks/React.qll index d55ace8636df..946b09ffd44b 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/React.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/React.qll @@ -612,6 +612,25 @@ private class UseStateStep extends PreCallGraphStep { } } +/** + * Step through a `useRef` call. + * + * It returns a pair of the initial state, and an object with a single property (current) potentially containing an input value. + * + * For example: + * ```js + * const inputRef1 = useRef(initialValue); + * ``` + */ +private class UseRefStep extends PreCallGraphStep { + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + exists(DataFlow::CallNode call | call = react().getAMemberCall("useRef") | + pred = call.getArgument(0) and // initial state + succ = call.getAPropertyRead("current") + ) + } +} + /** * A step through a React context object. * From dd6db165504476a6b93702a2d9f429cced89ef85 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 22 Oct 2025 16:51:03 -0400 Subject: [PATCH 2/5] Add DomValueSource for react useRef output (object's prop named current) --- .../change-notes/2025-10-21-react-precallgraph-step.md | 3 ++- .../ql/lib/semmle/javascript/frameworks/React.qll | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/change-notes/2025-10-21-react-precallgraph-step.md b/javascript/ql/lib/change-notes/2025-10-21-react-precallgraph-step.md index efba56b34707..e28a900e8d9c 100644 --- a/javascript/ql/lib/change-notes/2025-10-21-react-precallgraph-step.md +++ b/javascript/ql/lib/change-notes/2025-10-21-react-precallgraph-step.md @@ -1,4 +1,5 @@ --- category: minorAnalysis --- -* Added PreCallGraphStep flow model for React's `useRef` hook. \ No newline at end of file +* Added `PreCallGraphStep` flow model for React's `useRef` hook. +* Added a `DomValueSource` that uses the `current` property off the object returned by React's `useRef` hook. \ No newline at end of file diff --git a/javascript/ql/lib/semmle/javascript/frameworks/React.qll b/javascript/ql/lib/semmle/javascript/frameworks/React.qll index 946b09ffd44b..05d8db6a0755 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/React.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/React.qll @@ -804,6 +804,16 @@ private class ReactRouterLocationSource extends DOM::LocationSource::Range { } } +private class UseRefDomValueSource extends DOM::DomValueSource::Range { + UseRefDomValueSource() { + exists(DataFlow::PropRead current, UseRefStep step, string prop | current = this | + step.step(_, current) and + current.mayHavePropertyName(prop) and + prop = "current" + ) + } +} + /** * Gets a reference to a function which, if called with a React component, returns wrapped * version of that component, which we model as a direct reference to the underlying component. From 7f8ccb7d46509e464160d7667cf0d734a95fa858 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 22 Oct 2025 17:15:59 -0400 Subject: [PATCH 3/5] Simplify addition --- javascript/ql/lib/semmle/javascript/frameworks/React.qll | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/React.qll b/javascript/ql/lib/semmle/javascript/frameworks/React.qll index 05d8db6a0755..c68b6846a5bc 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/React.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/React.qll @@ -806,10 +806,9 @@ private class ReactRouterLocationSource extends DOM::LocationSource::Range { private class UseRefDomValueSource extends DOM::DomValueSource::Range { UseRefDomValueSource() { - exists(DataFlow::PropRead current, UseRefStep step, string prop | current = this | + exists(DataFlow::PropRead current, UseRefStep step | current = this | step.step(_, current) and - current.mayHavePropertyName(prop) and - prop = "current" + current.mayHavePropertyName("current") ) } } From ee60f8e6c6eb6002b37d2b7d2c1c681c6c5cef13 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Thu, 23 Oct 2025 09:57:10 -0400 Subject: [PATCH 4/5] Update javascript/ql/lib/semmle/javascript/frameworks/React.qll Co-authored-by: Asger F --- .../ql/lib/semmle/javascript/frameworks/React.qll | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/React.qll b/javascript/ql/lib/semmle/javascript/frameworks/React.qll index c68b6846a5bc..1c321ae1c12b 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/React.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/React.qll @@ -806,10 +806,12 @@ private class ReactRouterLocationSource extends DOM::LocationSource::Range { private class UseRefDomValueSource extends DOM::DomValueSource::Range { UseRefDomValueSource() { - exists(DataFlow::PropRead current, UseRefStep step | current = this | - step.step(_, current) and - current.mayHavePropertyName("current") - ) + this = + any(JsxAttribute attrib | attrib.getName() = "ref") + .getValue() + .flow() + .getALocalSource() + .getAPropertyRead("current") } } From 7b8a3d044ea3cd32fa4f4a82a3005691613ed742 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Tue, 28 Oct 2025 11:33:45 -0400 Subject: [PATCH 5/5] Update javascript/ql/lib/semmle/javascript/frameworks/React.qll Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- javascript/ql/lib/semmle/javascript/frameworks/React.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/React.qll b/javascript/ql/lib/semmle/javascript/frameworks/React.qll index 1c321ae1c12b..42885f6b9cb4 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/React.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/React.qll @@ -615,7 +615,7 @@ private class UseStateStep extends PreCallGraphStep { /** * Step through a `useRef` call. * - * It returns a pair of the initial state, and an object with a single property (current) potentially containing an input value. + * It returns an object with a single property (`current`) initialized to the initial value. * * For example: * ```js