From c43856d8ea7649e110de52ae4337dcbd1bbc1e43 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 1 Mar 2024 21:30:04 +0100 Subject: [PATCH] JS: Add steps to better handle module interop code --- .../semmle/javascript/dataflow/DataFlow.qll | 1 + .../dataflow/internal/ModuleInterop.qll | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 javascript/ql/lib/semmle/javascript/dataflow/internal/ModuleInterop.qll diff --git a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll index c098c60816e..e164adf786f 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll @@ -24,6 +24,7 @@ private import internal.FlowSteps as FlowSteps private import internal.DataFlowNode private import internal.AnalyzedParameters private import internal.PreCallGraphStep +private import internal.ModuleInterop private import semmle.javascript.internal.CachedStages module DataFlow { diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/ModuleInterop.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/ModuleInterop.qll new file mode 100644 index 00000000000..47a26350f97 --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/ModuleInterop.qll @@ -0,0 +1,46 @@ +private import javascript +private import PreCallGraphStep as PCG + +class ES2015InteropCall extends DataFlow::CallNode { + ES2015InteropCall() { + this.getCalleeName() = ["_interopRequireDefault", "_interopRequireWildcard"] + } + + private Import getAnImport() { + this.getArgument(0).getALocalSource() = result.getImportedModuleNode() + } + + Module getImportedModule() { result = this.getAnImport().getImportedModule() } + + predicate isImportingESModule() { + this.getImportedModule() instanceof ES2015Module + or + exists(this.getImportedModule().getAnExportedValue("__esModule")) + } + + DataFlow::SourceNode getImportedObject() { + this.isImportingESModule() and + result = this + or + (not this.isImportingESModule() or this.getCalleeName() = "_interopRequireWildcard") and + result = this.getAPropertyRead("default") + } +} + +predicate interopModuleStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(ES2015InteropCall call | + pred = call.getArgument(0) and + succ = call.getImportedObject() + or + exists(string prop | + pred = call.getImportedModule().getAnExportedValue(prop) and + succ = call.getImportedObject().getAPropertyRead(prop) + ) + ) +} + +private class Step extends PCG::PreCallGraphStep { + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + interopModuleStep(pred, succ) + } +}