Skip to content

Instantly share code, notes, and snippets.

@bayotop
Last active December 4, 2018 08:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bayotop/21d43d081ad51efeff9b4a62458e9daf to your computer and use it in GitHub Desktop.
Save bayotop/21d43d081ad51efeff9b4a62458e9daf to your computer and use it in GitHub Desktop.
Identify "href" (i.e., free "javascript:" XSS) and dangerouslySetInnerHtml usages in ReactJS SPAs.
import re
import sys
VULNERABLE_HREF = r'href: [^"].+[^\s]?'
DANGEROUSLY_SET_INNER_HTML = r'__html: .+[^\s]?'
STATE_VALUES = r'\.setState\({([\s\S]*?)}\)'
#false_positives = ("this.props.team.", "constants.")
def find_state_candidates(name, states):
candidates = []
for state in states:
for param in state.split('\n'):
param = param.rstrip(',;').strip()
if param.split(':')[0] == name:
candidates.append(param.split(':')[1].strip())
return candidates
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: %s beautified.js" % sys.argv[0])
sys.exit()
with open(sys.argv[1], 'r', errors="ignore") as f:
content = f.read()
matches = re.findall(VULNERABLE_HREF, content) + re.findall(DANGEROUSLY_SET_INNER_HTML, content)
states = re.findall(STATE_VALUES, content, flags=re.MULTILINE)
matches = [re.sub(' +', ' ', match).strip() for match in matches]
states = [re.sub(' +', ' ', state).strip() for state in states]
for match in matches:
value = match.split(' ')[1]
# if not value.startswith(false_positives):
if value.startswith('this.state.'):
print("%s (%s)" % (match, find_state_candidates(value.split('.')[2], states)))
else:
print(match)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment