diff --git a/javascript/ql/lib/semmle/javascript/endpoints/EndpointNaming.qll b/javascript/ql/lib/semmle/javascript/endpoints/EndpointNaming.qll index eb2fa714a394..fdb2b7ab9669 100644 --- a/javascript/ql/lib/semmle/javascript/endpoints/EndpointNaming.qll +++ b/javascript/ql/lib/semmle/javascript/endpoints/EndpointNaming.qll @@ -277,9 +277,16 @@ private predicate nameFromGlobal(DataFlow::Node node, string package, string nam (if node.getTopLevel().isExterns() then badness = -10 else badness = 10) } +/** Gets an API node whose value is exposed to client code. */ +private API::Node exposedNode() { + result = API::moduleExport(_) + or + result = exposedNode().getASuccessor() +} + /** Holds if an instance of `cls` can be exposed to client code. */ private predicate hasEscapingInstance(DataFlow::ClassNode cls) { - cls.getAnInstanceReference().flowsTo(any(API::Node n).asSink()) + cls.getAnInstanceReference().flowsTo(exposedNode().asSink()) } private predicate sourceNodeHasNameCandidate( diff --git a/javascript/ql/test/library-tests/EndpointNaming/pack1/main.js b/javascript/ql/test/library-tests/EndpointNaming/pack1/main.js index cc550f0da15b..53269fb0602b 100644 --- a/javascript/ql/test/library-tests/EndpointNaming/pack1/main.js +++ b/javascript/ql/test/library-tests/EndpointNaming/pack1/main.js @@ -13,3 +13,9 @@ export function getEscapingInstance() { } // $ name=(pack1).getEscapingInstance export function publicFunction() {} // $ name=(pack1).publicFunction + +// Escapes into an upstream library, but is not exposed downstream +class InternalClass { + m() {} +} +require('foo').bar(new InternalClass());