From 1253553aeccd237d09d2c7d0f3a8aaf968ec114a Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 25 Feb 2026 09:09:51 +0100 Subject: [PATCH] JS: Add browser source kinds --- .../frameworks/data/ModelsAsData.qll | 12 +++++++ .../security/dataflow/RemoteFlowSources.qll | 36 ++++++++++++------- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll index e4adff2a9ac..391f2ea1b33 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll @@ -35,6 +35,18 @@ private class RemoteFlowSourceFromMaD extends RemoteFlowSource { override string getSourceType() { result = "Remote flow" } } +private class ClientSideRemoteFlowSourceFromMaD extends ClientSideRemoteFlowSource { + private ClientSideRemoteFlowKind kind; + + ClientSideRemoteFlowSourceFromMaD() { ModelOutput::sourceNode(this, kind) } + + override ClientSideRemoteFlowKind getKind() { result = kind } + + override string getSourceType() { + result = "Source node (" + this.getThreatModel() + ") [from data-extension]" + } +} + /** * A threat-model flow source originating from a data extension. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll index 9f4975e605a..5b1424fb86e 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll @@ -43,35 +43,47 @@ import Cached /** * A type of remote flow source that is specific to the browser environment. + * + * The underlying string also corresponds to a source kind. */ class ClientSideRemoteFlowKind extends string { ClientSideRemoteFlowKind() { - this = ["query", "fragment", "path", "url", "name", "message-event"] + this = + [ + "browser", "browser-url-query", "browser-url-fragment", "browser-url-path", "browser-url", + "browser-window-name", "browser-message-event" + ] } /** - * Holds if this is the `query` kind, describing sources derived from the query parameters of the browser URL, + * Holds if this is the `browser` kind, indicating a remote source in a browser context, that does not fit into one + * of the more specific kinds. + */ + predicate isGenericBrowserSourceKind() { this = "browser" } + + /** + * Holds if this is the `browser-url-query` kind, describing sources derived from the query parameters of the browser URL, * such as `location.search`. */ - predicate isQuery() { this = "query" } + predicate isQuery() { this = "browser-url-query" } /** - * Holds if this is the `frgament` kind, describing sources derived from the fragment part of the browser URL, + * Holds if this is the `browser-url-fragment` kind, describing sources derived from the fragment part of the browser URL, * such as `location.hash`. */ - predicate isFragment() { this = "fragment" } + predicate isFragment() { this = "browser-url-fragment" } /** - * Holds if this is the `path` kind, describing sources derived from the pathname of the browser URL, + * Holds if this is the `browser-url-path` kind, describing sources derived from the pathname of the browser URL, * such as `location.pathname`. */ - predicate isPath() { this = "path" } + predicate isPath() { this = "browser-url-path" } /** - * Holds if this is the `url` kind, describing sources derived from the browser URL, + * Holds if this is the `browser-url` kind, describing sources derived from the browser URL, * where the untrusted part of the URL is prefixed by trusted data, such as the scheme and hostname. */ - predicate isUrl() { this = "url" } + predicate isUrl() { this = "browser-url" } /** Holds if this is the `query` or `fragment` kind. */ predicate isQueryOrFragment() { this.isQuery() or this.isFragment() } @@ -83,13 +95,13 @@ class ClientSideRemoteFlowKind extends string { predicate isPathOrUrl() { this.isPath() or this.isUrl() } /** Holds if this is the `name` kind, describing sources derived from the window name, such as `window.name`. */ - predicate isWindowName() { this = "name" } + predicate isWindowName() { this = "browser-window-name" } /** - * Holds if this is the `message-event` kind, describing sources derived from cross-window message passing, + * Holds if this is the `browser-message-event` kind, describing sources derived from cross-window message passing, * such as `event` in `window.onmessage = event => {...}`. */ - predicate isMessageEvent() { this = "message-event" } + predicate isMessageEvent() { this = "browser-message-event" } } /**