Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions javascript/frameworks/ui5/src/Diagnostics/InvestigateReact.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* @name List properties of react modelling
* @description List properties of react modelling
* @ kind problem
* @problem.severity info
* @precision high
* @id js/ui5-investigate-react
* @tags diagnostics
*/

import javascript
import semmle.javascript.security.dataflow.XssThroughDomQuery
import semmle.javascript.security.dataflow.XssThroughDomCustomizations

from DataFlow::Node source
where source instanceof XssThroughDom::Source
select source, ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Input, Button } from '@ui5/webcomponents-react';
import { useRef, useState } from 'react';
import type { InputDomRef } from '@ui5/webcomponents-react';

function ControlledComponent( { props }) {
const inputRef1 = useRef < InputDomRef > (null);
const [inputRef2, setInputValue] = useState('');

const handleButtonPress1 = () => {
// Access the input value via the hook
console.log('Current input value:', inputRef1.current.value); // SOURCE - not detected
};

const handleButtonPress2 = event => {
setInputValue(event.target.value); // SOURCE - detected
console.log('Current input value:', inputRef2); // not directly a source
};

return (
<div>
<Input
ref={inputRef1}
placeholder="Enter some text"
/>
<Button onClick={handleButtonPress1}>
Get Input Value
</Button>
<Input
placeholder="Enter some text"
value={inputRef2}
/>
<Button onClick={handleButtonPress2}>
Get Input Value
</Button>
</div>
);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React, { useState } from 'react';

function MyFunctionalComponent({ props }) {
const [count, setState] = useState({ count: 0 });

const handleClick = event => {
setState({ count: event.target.value + 1 }); // SOURCE - detected as event.target.value
console.log('Current input value:', count);
};

return (
<div>
<input value={count.count} onChange={handleClick}></input>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Input } from '@ui5/webcomponents-react';

// normal react component props
function ChildComponent({ value }) { // SOURCE

console.log('Input finalized with value:', value);

return (
<div>
<Input
placeholder={value}
/>
</div>
);
}

function ParentComponent() {
const data = "Hello from Parent";
return <ChildComponent value={data} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
| controlledcomponent.tsx:15:23:15:40 | event.target.value | |
| functionalcomponentsetstate.tsx:7:23:7:40 | event.target.value | |
| uncontrolledcomponent.tsx:9:24:9:41 | event.target.value | |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Diagnostics/InvestigateReact.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Input, Button } from '@ui5/webcomponents-react';
import type { InputDomRef } from '@ui5/webcomponents-react';
import type { Ui5CustomEvent } from '@ui5/webcomponents-react-base';

function UncontrolledComponent({ props }) {

//direct event value access, no hook/react specific function
const handleClick = (event: Ui5CustomEvent<InputDomRef>) => {
const finalValue = event.target.value; // SOURCE - detected
console.log('Input finalized with value:', finalValue);
};

return (
<div>
<Input
placeholder="Enter some text"
onChange={handleClick}
/>
<Button>
Get Input Value
</Button>
</div>
);
}