diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll index f5cbbc39f73..b6c47a37577 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll @@ -844,6 +844,12 @@ module ClassNode { override DataFlow::Node getASuperClassNode() { result = astNode.getSuperClass().flow() } } + private DataFlow::PropRef getAPrototypeReferenceInFile(string name, File f) { + GlobalAccessPath::getAccessPath(result.getBase()) = name and + result.getPropertyName() = "prototype" and + result.getFile() = f + } + /** * A function definition with prototype manipulation as a `ClassNode` instance. */ @@ -854,9 +860,16 @@ module ClassNode { FunctionStyleClass() { function.getFunction() = astNode and - exists(DataFlow::PropRef read | - read.getPropertyName() = "prototype" and - read.getBase().analyze().getAValue() = function + ( + exists (DataFlow::PropRef read | + read.getPropertyName() = "prototype" and + read.getBase().analyze().getAValue() = function + ) + or + exists(string name | + name = GlobalAccessPath::fromRhs(this) and + exists(getAPrototypeReferenceInFile(name, getFile())) + ) ) } @@ -916,11 +929,16 @@ module ClassNode { result = base.getAPropertyRead("prototype") or result = base.getAPropertySource("prototype") - or - exists(ExtendCall call | - call.getDestinationOperand() = base.getAPropertyRead("prototype") and - result = call.getASourceOperand() - ) + ) + or + exists(string name | + GlobalAccessPath::fromRhs(this) = name and + result = getAPrototypeReferenceInFile(name, getFile()) + ) + or + exists(ExtendCall call | + call.getDestinationOperand() = getAPrototypeReference() and + result = call.getASourceOperand() ) }