From 8cc75bbd9ee80dee85a8363b20f3897231af058c Mon Sep 17 00:00:00 2001 From: GeekMasher Date: Thu, 17 Apr 2025 10:38:23 +0100 Subject: [PATCH 1/3] feat(go): Update dependencies and add GHSL sources and sinks implementation --- go/lib/codeql-pack.lock.yml | 16 ++++++------- go/lib/ghsl.qll | 4 ++++ go/lib/ghsl/Sinks.qll | 48 +++++++++++++++++++++++++++++++++++++ go/lib/ghsl/Utils.qll | 43 +++++++++++++++++++++++++++++++-- 4 files changed, 101 insertions(+), 10 deletions(-) create mode 100644 go/lib/ghsl.qll create mode 100644 go/lib/ghsl/Sinks.qll diff --git a/go/lib/codeql-pack.lock.yml b/go/lib/codeql-pack.lock.yml index e54c0957..cc844e57 100644 --- a/go/lib/codeql-pack.lock.yml +++ b/go/lib/codeql-pack.lock.yml @@ -2,19 +2,19 @@ lockVersion: 1.0.0 dependencies: codeql/dataflow: - version: 1.1.8 + version: 2.0.4 codeql/go-all: - version: 3.0.1 + version: 4.2.2 codeql/mad: - version: 1.0.14 + version: 1.0.20 codeql/ssa: - version: 1.0.14 + version: 1.0.20 codeql/threat-models: - version: 1.0.14 + version: 1.0.20 codeql/tutorial: - version: 1.0.14 + version: 1.0.20 codeql/typetracking: - version: 1.0.14 + version: 2.0.4 codeql/util: - version: 2.0.1 + version: 2.0.7 compiled: false diff --git a/go/lib/ghsl.qll b/go/lib/ghsl.qll new file mode 100644 index 00000000..d86db815 --- /dev/null +++ b/go/lib/ghsl.qll @@ -0,0 +1,4 @@ +import go +import ghsl.Utils +import ghsl.LocalSources +import ghsl.Sinks \ No newline at end of file diff --git a/go/lib/ghsl/Sinks.qll b/go/lib/ghsl/Sinks.qll new file mode 100644 index 00000000..b82b677e --- /dev/null +++ b/go/lib/ghsl/Sinks.qll @@ -0,0 +1,48 @@ +private import go +private import semmle.go.dataflow.DataFlow +private import semmle.go.security.CommandInjectionCustomizations +private import semmle.go.security.OpenUrlRedirectCustomizations +private import semmle.go.security.ReflectedXssCustomizations +private import semmle.go.security.RequestForgeryCustomizations +private import semmle.go.security.SqlInjectionCustomizations +private import semmle.go.security.UnsafeUnzipSymlinkCustomizations +private import semmle.go.security.XPathInjectionCustomizations +private import semmle.go.security.ZipSlipCustomizations + +/** + * List of all the sinks that we want to check. + */ +class AllSinks extends DataFlow::Node { + private string sink; + + AllSinks() { + this instanceof CommandInjection::Sink and + sink = "command-injection" + or + this instanceof OpenUrlRedirect::Sink and + sink = "open-url-redirect" + or + this instanceof ReflectedXss::Sink and + sink = "reflected-xss" + or + this instanceof RequestForgery::Sink and + sink = "request-forgery" + or + this instanceof SqlInjection::Sink and + sink = "sql-injection" + or + this instanceof UnsafeUnzipSymlink::EvalSymlinksSink and + sink = "unsafe-unzip" + or + this instanceof XPathInjection::Sink and + sink = "xpath-injection" + or + this instanceof ZipSlip::Sink and + sink = "zip-slip" + } + + /** + * Gets the sink sink type. + */ + string sinkType() { result = sink } +} diff --git a/go/lib/ghsl/Utils.qll b/go/lib/ghsl/Utils.qll index 9a27b5d4..0b593280 100644 --- a/go/lib/ghsl/Utils.qll +++ b/go/lib/ghsl/Utils.qll @@ -1,5 +1,44 @@ -import go -import semmle.go.frameworks.stdlib.Fmt +private import go +private import semmle.go.dataflow.DataFlow +private import semmle.go.dataflow.TaintTracking +private import semmle.go.frameworks.stdlib.Fmt + +/** + * Find Node at Location + */ +predicate filterByLocation(DataFlow::Node node, string relative_path, int linenumber) { + node.getLocation().getFile().getRelativePath() = relative_path and + node.getLocation().getStartLine() = linenumber +} + +/** + * List of all the souces + */ +class AllSources extends DataFlow::Node { + private string threatmodel; + + AllSources() { + this instanceof RemoteFlowSource::Range and + threatmodel = "remote" + or + this instanceof LocalSources and + threatmodel = "local" + } + + /** + * Gets the source threat model. + */ + string getThreatModel() { result = threatmodel } +} + +/** + * Local sources + */ +class LocalSources extends DataFlow::Node { + LocalSources() { + this.(SourceNode).getThreatModel() = "local" + } +} class DynamicStrings extends DataFlow::Node { DynamicStrings() { From 5c360a999c0b5edcce14ce34a7a98ca6034f8444 Mon Sep 17 00:00:00 2001 From: GeekMasher Date: Thu, 17 Apr 2025 10:40:28 +0100 Subject: [PATCH 2/3] feat(go): Add Sinks and Sources queries with query suite --- go/src/debugging/Sinks.ql | 15 +++++++++++++++ go/src/debugging/Sources.ql | 18 ++++++++++++++++++ go/src/suites/go-debugging.qls | 19 +++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 go/src/debugging/Sinks.ql create mode 100644 go/src/debugging/Sources.ql create mode 100644 go/src/suites/go-debugging.qls diff --git a/go/src/debugging/Sinks.ql b/go/src/debugging/Sinks.ql new file mode 100644 index 00000000..f63a5f41 --- /dev/null +++ b/go/src/debugging/Sinks.ql @@ -0,0 +1,15 @@ +/** + * @name List of all known sinks + * @kind problem + * @problem.severity warning + * @security-severity 1.0 + * @sub-severity low + * @precision high + * @id go/debugging/sinks + * @tags debugging + */ + +import ghsl + +from AllSinks sinks +select sinks, "sink[" + sinks.sinkType() + "]" diff --git a/go/src/debugging/Sources.ql b/go/src/debugging/Sources.ql new file mode 100644 index 00000000..7aa97830 --- /dev/null +++ b/go/src/debugging/Sources.ql @@ -0,0 +1,18 @@ +/** + * @name List of all known sources (remote, local, etc.) + * @kind problem + * @problem.severity warning + * @security-severity 1.0 + * @sub-severity low + * @precision high + * @id go/debugging/sources + * @tags debugging + */ + +import ghsl + +from AllSources sources, string threatModel +where threatModel = sources.getThreatModel() +// Local sources +// sources.getThreatModel() = "local" +select sources, "source[" + threatModel + "]" diff --git a/go/src/suites/go-debugging.qls b/go/src/suites/go-debugging.qls new file mode 100644 index 00000000..d1970fe4 --- /dev/null +++ b/go/src/suites/go-debugging.qls @@ -0,0 +1,19 @@ +- description: "GitHub's Community Packs Go Debugging Suite" + +- queries: '.' + from: githubsecuritylab/codeql-go-queries + +- include: + kind: + - problem + - path-problem + precision: + - very-high + - high + tags contain: + - debugging + +# Remove local testing folders +- exclude: + query path: + - /testing\/.*/ \ No newline at end of file From 48975a8ea14e8df339953ca9c8441631cd9af282 Mon Sep 17 00:00:00 2001 From: GeekMasher Date: Thu, 17 Apr 2025 10:44:50 +0100 Subject: [PATCH 3/3] feat(go): Add Partial Path queries --- go/src/debugging/PartialPathsFromSink.ql | 40 ++++++++++++++++++++++ go/src/debugging/PartialPathsFromSource.ql | 39 +++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 go/src/debugging/PartialPathsFromSink.ql create mode 100644 go/src/debugging/PartialPathsFromSource.ql diff --git a/go/src/debugging/PartialPathsFromSink.ql b/go/src/debugging/PartialPathsFromSink.ql new file mode 100644 index 00000000..8d8da90b --- /dev/null +++ b/go/src/debugging/PartialPathsFromSink.ql @@ -0,0 +1,40 @@ +/** + * @name Partial Path Query from Sink + * @kind path-problem + * @problem.severity warning + * @security-severity 1.0 + * @sub-severity low + * @precision low + * @id go/debugging/partial-path-from-sink + * @tags debugging + */ + +import go +import ghsl +import semmle.go.dataflow.DataFlow +import semmle.go.dataflow.TaintTracking + +// Partial Graph +module PartialFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { any() } + + predicate isSink(DataFlow::Node sink) { sink instanceof AllSinks } +} + +int explorationLimit() { result = 10 } + +private module PartialFlows = DataFlow::Global; + +private module PartialFlowsGraph = PartialFlows::FlowExplorationRev; + +private import PartialFlowsGraph::PartialPathGraph + +from PartialFlowsGraph::PartialPathNode source, PartialFlowsGraph::PartialPathNode sink +where + /// Only show sinks from a certain file + // findByLocation(sink.getNode(), "main.go", _) and + /// Only show sources that match our criteria + // checkSource(source.getNode()) and + /// Partical Path + PartialFlowsGraph::partialFlow(source, sink, _) +select sink.getNode(), source, sink, "Partial Graph $@.", source.getNode(), "user-provided value" \ No newline at end of file diff --git a/go/src/debugging/PartialPathsFromSource.ql b/go/src/debugging/PartialPathsFromSource.ql new file mode 100644 index 00000000..3276f1d2 --- /dev/null +++ b/go/src/debugging/PartialPathsFromSource.ql @@ -0,0 +1,39 @@ +/** + * @name Partial Path Query from Source + * @kind path-problem + * @problem.severity warning + * @security-severity 1.0 + * @sub-severity low + * @precision low + * @id py/debugging/partial-path-from-source + * @tags debugging + */ + +import go +import ghsl +import semmle.go.dataflow.DataFlow +import semmle.go.dataflow.TaintTracking + +// Partial Graph +module PartialFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + source instanceof AllSources + } + + predicate isSink(DataFlow::Node sink) { none() } +} + +int explorationLimit() { result = 10 } + +module PartialFlows = DataFlow::Global; + +module PartialFlowsGraph = PartialFlows::FlowExplorationFwd; + +import PartialFlowsGraph::PartialPathGraph + +from PartialFlowsGraph::PartialPathNode source, PartialFlowsGraph::PartialPathNode sink +where + /// Filter by location + // filterByLocation(source.getNode(), "main.go", _) + PartialFlowsGraph::partialFlow(source, sink, _) +select sink.getNode(), source, sink, "Partial Graph $@.", source.getNode(), "user-provided value"