diff --git a/go/ql/lib/semmle/go/security/UnicodeBypassValidationCustomizations.qll b/go/ql/lib/semmle/go/security/UnicodeBypassValidationCustomizations.qll new file mode 100644 index 000000000000..ae721c1ab469 --- /dev/null +++ b/go/ql/lib/semmle/go/security/UnicodeBypassValidationCustomizations.qll @@ -0,0 +1,29 @@ +/** + * Provides default sources, sinks and sanitizers for detecting + * "Unicode transformation" + * vulnerabilities, as well as extension points for adding your own. + */ + +private import go + +/** + * Provides default sources, sinks and sanitizers for detecting + * "Unicode transformation" + * vulnerabilities, as well as extension points for adding your own. + */ +module UnicodeBypassValidation { + /** + * A data flow source for "Unicode transformation" vulnerabilities. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for "Unicode transformation" vulnerabilities. + */ + abstract class Sink extends DataFlow::Node { } + + /** + * A sanitizer for "Unicode transformation" vulnerabilities. + */ + abstract class Sanitizer extends DataFlow::Node { } +} diff --git a/go/ql/lib/semmle/go/security/UnicodeBypassValidationQuery.qll b/go/ql/lib/semmle/go/security/UnicodeBypassValidationQuery.qll new file mode 100644 index 000000000000..13622770455e --- /dev/null +++ b/go/ql/lib/semmle/go/security/UnicodeBypassValidationQuery.qll @@ -0,0 +1,179 @@ +/** + * Provides a taint-tracking configuration for detecting "Unicode transformation mishandling" vulnerabilities. + */ + +private import go +import semmle.go.Concepts +import semmle.go.dataflow.DataFlow +import semmle.go.dataflow.TaintTracking +import UnicodeBypassValidationCustomizations::UnicodeBypassValidation + +/** A state signifying that a logical validation has not been performed. */ +class PreValidation extends DataFlow::FlowState { + PreValidation() { this = "PreValidation" } +} + +/** A state signifying that a logical validation has been performed. */ +class PostValidation extends DataFlow::FlowState { + PostValidation() { this = "PostValidation" } +} + +private predicate indexCheck(DataFlow::Node g, Expr e, boolean outcome) { + exists(DataFlow::CallNode cn, DataFlow::EqualityTestNode etn | + g = etn and + DataFlow::localFlow(cn.getResult(), etn.getAnOperand()) and + cn.getTarget() + .hasQualifiedName("strings", + [ + "Index", "IndexAny", "IndexByte", "IndexFunc", "IndexRune", "LastIndex", "LastIndexAny", + "LastIndexByte", "LastIndexFunc", + ]) and + cn.getArgument(0).asExpr() = e and + etn.getAnOperand().getIntValue() = -1 and + outcome = etn.getPolarity() + ) +} + +private predicate countCheck(DataFlow::Node g, Expr e, boolean outcome) { + exists( + DataFlow::RelationalComparisonNode cmp, DataFlow::CallNode cn, DataFlow::Node zero, + DataFlow::Node r + | + g = cmp and + DataFlow::localFlow(cn.getResult(), r) and + cn.getTarget().hasQualifiedName("strings", "Count") and + cn.getArgument(1).asExpr() = e and + zero.getNumericValue() = 0 and + cmp.leq(outcome, r, zero, 0) + ) +} + +private predicate boolCheck(DataFlow::Node cn, Expr e, boolean outcome) { + cn.(DataFlow::CallNode) + .getTarget() + .hasQualifiedName("strings", + ["Contains", "ContainsAny", "ContainsRune", "HasPrefix", "HasSuffix", "EqualFold"]) and + cn.(DataFlow::CallNode).getArgument(0).asExpr() = e and + outcome = false +} + +private predicate compareCheck(DataFlow::Node cn, Expr e, boolean outcome) { + cn.(DataFlow::CallNode) + .getTarget() + .hasQualifiedName("strings", ["Compare", "CompareFold", "ComparePrefix", "CompareSuffix"]) and + cn.(DataFlow::CallNode).getArgument(0).asExpr() = e and + outcome = false +} + +private predicate regexMatchCheck(DataFlow::Node cn, Expr e, boolean outcome) { + cn.(DataFlow::CallNode).getTarget() instanceof RegexpMatchFunction and + cn.(DataFlow::CallNode).getArgument(0).asExpr() = e and + outcome = false +} + +/** + * A use of a variable guarded by a call to `Index`, `ContainsAny`, Regex match functions + * or similar, in a context suggesting it has been validated to not contain a particular character. + */ +class UntrustedUnicodeCharChecks extends DataFlow::Node { + UntrustedUnicodeCharChecks() { + this = DataFlow::BarrierGuard::getABarrierNode() + or + this = DataFlow::BarrierGuard::getABarrierNode() + or + this = DataFlow::BarrierGuard::getABarrierNode() + or + this = DataFlow::BarrierGuard::getABarrierNode() + or + this = DataFlow::BarrierGuard::getABarrierNode() + } +} + +/** + * A taint-tracking configuration for detecting "Unicode transformation mishandling" vulnerabilities. + * + * This configuration uses two flow states, `PreValidation` and `PostValidation`, + * to track the requirement that a logical validation has been performed before the Unicode Transformation. + */ +class Configuration extends TaintTracking::Configuration { + Configuration() { this = "UnicodeBypassValidation" } + + override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { + (source instanceof UntrustedFlowSource or source instanceof Source) and + state instanceof PreValidation + } + + override predicate isSanitizer(DataFlow::Node sanitizer, DataFlow::FlowState state) { + sanitizer instanceof Sanitizer and + state instanceof PostValidation + } + + override predicate isAdditionalTaintStep( + DataFlow::Node nodeFrom, DataFlow::FlowState stateFrom, DataFlow::Node nodeTo, + DataFlow::FlowState stateTo + ) { + ( + exists(DataFlow::CallNode cn | + cn.getACalleeIncludingExternals().asFunction() instanceof EscapeFunction and + nodeFrom = cn.getAnArgument() and + nodeTo = cn.getResult() + ) + or + exists(DataFlow::CallNode cn | + cn.getACalleeIncludingExternals().asFunction() instanceof RegexpReplaceFunction and + nodeFrom = cn.getAnArgument() and + nodeTo = cn.getResult() + ) + or + exists(DataFlow::CallNode cn | + cn.getTarget().hasQualifiedName("strings", "Cut") and + nodeFrom = cn.getArgument(0) and + nodeTo = cn.getResult([0, 1]) + ) + or + exists(DataFlow::CallNode cn | + cn.getTarget().hasQualifiedName("strings", ["CutPrefix", "CutSuffix"]) and + nodeFrom = cn.getArgument(0) and + nodeTo = cn.getResult(0) + ) + or + exists(DataFlow::CallNode cn | + cn.getTarget() + .hasQualifiedName("strings", + [ + "Fields", "FieldsFunc", "Replace", "ReplaceAll", "Split", "SplitAfter", + "SplitAfterN", "SplitN", "ToLower", "ToLowerSpecial", "ToTitle", "ToTitleSpecial", + "ToUpper", "ToUpperSpecial", "Trim", "TrimFunc", "TrimLeft", "TrimLeftFunc", + "TrimPrefix", "TrimRight", "TrimRightFunc", "TrimSpace", "TrimSuffix", + ]) and + nodeFrom = cn.getArgument(0) and + nodeTo = cn.getAResult() + ) + ) and + stateFrom instanceof PreValidation and + stateTo instanceof PostValidation + } + + /* + * A Unicode Tranformation is considered a sink when the form algorithm used is for Unicode normalization (NFC, NFKC, etc) and one of the two scenarios happens: + * - The flow went through a call to an Escape function, Regex Replace function, or a String manipulation function. + * - The Unicode normalisation was guarded by a check that the input does not contain a particular character either using Regex match functions or String checks functions like Index/Contains functions. + */ + + override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { + ( + exists(string unicodeNorm, DataFlow::MethodCallNode cn | + unicodeNorm = package("golang.org/x/text", "unicode/norm") and + cn.getTarget().hasQualifiedName(unicodeNorm, "Form", "String") and + sink = cn.getArgument(0) + ) + or + sink instanceof Sink + ) and + ( + state instanceof PostValidation + or + sink instanceof UntrustedUnicodeCharChecks and state instanceof PreValidation + ) + } +} diff --git a/go/ql/src/experimental/CWE-176/UnicodeBypassValidation.qhelp b/go/ql/src/experimental/CWE-176/UnicodeBypassValidation.qhelp new file mode 100644 index 000000000000..3ff907ffb42b --- /dev/null +++ b/go/ql/src/experimental/CWE-176/UnicodeBypassValidation.qhelp @@ -0,0 +1,34 @@ + + + +

+ If ever a unicode tranformation is performed after some security checks or logical + validation, those + checks could be bypassed due to a potential Unicode characters collision. + The validation of concern are any character escaping, any regex validation or any string + verification. +

+
+ +

Perform a Unicode normalization before the logical validation.

+
+ + +

The following example showcases the bypass of all checks performed by + html.EscapeString() due to a post-unicode normalization.

+

For instance: the character U+FE64 () is not filtered-out by the flask + escape function. But due to the Unicode normalization, the character is transformed and + would become U+003C ( < ).

+ + + +
+ +
  • Research study: + Unicode vulnerabilities that could bYte you + and Unicode pentest + cheatsheet.
  • +
    +
    \ No newline at end of file diff --git a/go/ql/src/experimental/CWE-176/UnicodeBypassValidation.ql b/go/ql/src/experimental/CWE-176/UnicodeBypassValidation.ql new file mode 100644 index 000000000000..80964274c3b3 --- /dev/null +++ b/go/ql/src/experimental/CWE-176/UnicodeBypassValidation.ql @@ -0,0 +1,24 @@ +/** + * @name Bypass Logical Validation Using Unicode Characters + * @description A Unicode transformation is using a remote user-controlled data. The transformation is a Unicode normalization . In all cases, the security measures implemented or the logical validation performed to escape any injection characters, to validate using regex patterns or to perform string-based checks, before the Unicode transformation are **bypassable** by special Unicode characters. + * @kind path-problem + * @id go/unicode-bypass-validation + * @precision high + * @problem.severity error + * @tags security + * experimental + * external/cwe/cwe-176 + * external/cwe/cwe-179 + * external/cwe/cwe-180 + */ + +import go +import semmle.go.security.UnicodeBypassValidationQuery +import DataFlow::PathGraph + +from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink.getNode(), source, sink, + "This $@ processes unsafely $@ and any logical validation in-between could be bypassed using special Unicode characters.", + sink.getNode(), "Unicode transformation (Unicode normalization)", source.getNode(), + "remote user-controlled data" diff --git a/go/ql/src/experimental/CWE-176/example.go b/go/ql/src/experimental/CWE-176/example.go new file mode 100644 index 000000000000..62841a552730 --- /dev/null +++ b/go/ql/src/experimental/CWE-176/example.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "html" + "net/http" + + "golang.org/x/text/unicode/norm" +) + +func main() {} + +func bad() { + http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + + unicode_input := req.URL.Query().Get("unicode_input") + escaped := html.EscapeString(unicode_input) + unicode_norm := norm.NFKC.String(escaped) + fmt.Println(w, "Results: %q", unicode_norm) + }) +} diff --git a/go/ql/test/experimental/CWE-176/UnicodeBypassValidation.expected b/go/ql/test/experimental/CWE-176/UnicodeBypassValidation.expected new file mode 100644 index 000000000000..639967f4a6af --- /dev/null +++ b/go/ql/test/experimental/CWE-176/UnicodeBypassValidation.expected @@ -0,0 +1,40 @@ +edges +| example_bad.go:17:20:17:26 | selection of URL | example_bad.go:17:20:17:34 | call to Query | +| example_bad.go:17:20:17:34 | call to Query | example_bad.go:17:20:17:55 | call to Get | +| example_bad.go:17:20:17:55 | call to Get | example_bad.go:18:32:18:44 | unicode_input | +| example_bad.go:18:14:18:45 | call to EscapeString | example_bad.go:19:36:19:42 | escaped | +| example_bad.go:18:32:18:44 | unicode_input | example_bad.go:18:14:18:45 | call to EscapeString | +| example_bad.go:25:20:25:26 | selection of URL | example_bad.go:25:20:25:34 | call to Query | +| example_bad.go:25:20:25:34 | call to Query | example_bad.go:25:20:25:55 | call to Get | +| example_bad.go:25:20:25:55 | call to Get | example_bad.go:27:37:27:49 | unicode_input | +| example_bad.go:35:20:35:26 | selection of URL | example_bad.go:35:20:35:34 | call to Query | +| example_bad.go:35:20:35:34 | call to Query | example_bad.go:35:20:35:55 | call to Get | +| example_bad.go:35:20:35:55 | call to Get | example_bad.go:37:37:37:49 | unicode_input | +| example_bad.go:45:20:45:26 | selection of URL | example_bad.go:45:20:45:34 | call to Query | +| example_bad.go:45:20:45:34 | call to Query | example_bad.go:45:20:45:55 | call to Get | +| example_bad.go:45:20:45:55 | call to Get | example_bad.go:47:37:47:49 | unicode_input | +nodes +| example_bad.go:17:20:17:26 | selection of URL | semmle.label | selection of URL | +| example_bad.go:17:20:17:34 | call to Query | semmle.label | call to Query | +| example_bad.go:17:20:17:55 | call to Get | semmle.label | call to Get | +| example_bad.go:18:14:18:45 | call to EscapeString | semmle.label | call to EscapeString | +| example_bad.go:18:32:18:44 | unicode_input | semmle.label | unicode_input | +| example_bad.go:19:36:19:42 | escaped | semmle.label | escaped | +| example_bad.go:25:20:25:26 | selection of URL | semmle.label | selection of URL | +| example_bad.go:25:20:25:34 | call to Query | semmle.label | call to Query | +| example_bad.go:25:20:25:55 | call to Get | semmle.label | call to Get | +| example_bad.go:27:37:27:49 | unicode_input | semmle.label | unicode_input | +| example_bad.go:35:20:35:26 | selection of URL | semmle.label | selection of URL | +| example_bad.go:35:20:35:34 | call to Query | semmle.label | call to Query | +| example_bad.go:35:20:35:55 | call to Get | semmle.label | call to Get | +| example_bad.go:37:37:37:49 | unicode_input | semmle.label | unicode_input | +| example_bad.go:45:20:45:26 | selection of URL | semmle.label | selection of URL | +| example_bad.go:45:20:45:34 | call to Query | semmle.label | call to Query | +| example_bad.go:45:20:45:55 | call to Get | semmle.label | call to Get | +| example_bad.go:47:37:47:49 | unicode_input | semmle.label | unicode_input | +subpaths +#select +| example_bad.go:19:36:19:42 | escaped | example_bad.go:17:20:17:26 | selection of URL | example_bad.go:19:36:19:42 | escaped | This $@ processes unsafely $@ and any logical validation in-between could be bypassed using special Unicode characters. | example_bad.go:19:36:19:42 | escaped | Unicode transformation (Unicode normalization) | example_bad.go:17:20:17:26 | selection of URL | remote user-controlled data | +| example_bad.go:27:37:27:49 | unicode_input | example_bad.go:25:20:25:26 | selection of URL | example_bad.go:27:37:27:49 | unicode_input | This $@ processes unsafely $@ and any logical validation in-between could be bypassed using special Unicode characters. | example_bad.go:27:37:27:49 | unicode_input | Unicode transformation (Unicode normalization) | example_bad.go:25:20:25:26 | selection of URL | remote user-controlled data | +| example_bad.go:37:37:37:49 | unicode_input | example_bad.go:35:20:35:26 | selection of URL | example_bad.go:37:37:37:49 | unicode_input | This $@ processes unsafely $@ and any logical validation in-between could be bypassed using special Unicode characters. | example_bad.go:37:37:37:49 | unicode_input | Unicode transformation (Unicode normalization) | example_bad.go:35:20:35:26 | selection of URL | remote user-controlled data | +| example_bad.go:47:37:47:49 | unicode_input | example_bad.go:45:20:45:26 | selection of URL | example_bad.go:47:37:47:49 | unicode_input | This $@ processes unsafely $@ and any logical validation in-between could be bypassed using special Unicode characters. | example_bad.go:47:37:47:49 | unicode_input | Unicode transformation (Unicode normalization) | example_bad.go:45:20:45:26 | selection of URL | remote user-controlled data | diff --git a/go/ql/test/experimental/CWE-176/UnicodeBypassValidation.go b/go/ql/test/experimental/CWE-176/UnicodeBypassValidation.go new file mode 100644 index 000000000000..65ec1b34aef3 --- /dev/null +++ b/go/ql/test/experimental/CWE-176/UnicodeBypassValidation.go @@ -0,0 +1,94 @@ +package main + +import ( + "fmt" + "html" + "net/http" + "regexp" + "strings" + + "golang.org/x/text/unicode/norm" +) + +func main() {} + +func bad() { + http.HandleFunc("/bad_1", func(w http.ResponseWriter, req *http.Request) { + // BAD: Unicode normalization is applied after escaping. + unicode_input := req.URL.Query().Get("unicode_input") + escaped := html.EscapeString(unicode_input) + unicode_norm := norm.NFKC.String(escaped) // $result=BAD + fmt.Println(w, "Results: %q", unicode_norm) + }) + + http.HandleFunc("/good_1", func(w http.ResponseWriter, req *http.Request) { + // GOOD: Unicode normalization is applied before escaping. + unicode_input := req.URL.Query().Get("unicode_input") + unicode_norm := norm.NFKC.String(unicode_input) // $result=OK + unicode_escaped := html.EscapeString(unicode_norm) + + fmt.Println(w, "Results: %q", unicode_escaped) + }) + + http.HandleFunc("/bad_2", func(w http.ResponseWriter, req *http.Request) { + + // BAD: Unicode normalization is performed after checking + // if any of the unsafe two characters "<<" is present, there may + // be more like the tricky "﹤" + unicode_input := req.URL.Query().Get("unicode_input") + ind := strings.IndexAny(unicode_input, "<<") + if ind == -1 { + unicode_norm := norm.NFKC.String(unicode_input) // $result=BAD + fmt.Println(w, "Results: %q", unicode_norm) + } else { + fmt.Println(w, "Potential unsafe characters used : %q", unicode_input) + } + + }) + + http.HandleFunc("/bad_3", func(w http.ResponseWriter, req *http.Request) { + + // BAD: Unicode normalization is guarded by the call to `ContainsAny()` which suggests that the + // input has been validated against the presence of the unsafe characters "<" or their unicode + // equivalents. This may not the be the case of all the possible Unicode equivalents. + unicode_input := req.URL.Query().Get("unicode_input") + if !strings.ContainsAny(unicode_input, "<﹤<") { + unicode_norm := norm.NFKC.String(unicode_input) // $result=BAD + fmt.Println(w, "Results: %q", unicode_norm) + } else { + fmt.Println(w, "Contains unsafe characters: %q", unicode_input) + } + + }) + + http.HandleFunc("/bad_4", func(w http.ResponseWriter, req *http.Request) { + + // BAD: Unicode normalization is performed after the regex match validation is performed + // against the unsafe characters "<" and ">". This may be bypassed using the Unicode characters + // equivalent to "<" and ">". + unicode_input := req.URL.Query().Get("unicode_input") + re := regexp.MustCompile("[<>]") + if !re.MatchString(unicode_input) { + unicode_norm := norm.NFKC.String(unicode_input) // $result=BAD + fmt.Println(w, "Results: %q", unicode_norm) + } else { + fmt.Println("The input is not safe.") + } + + }) + + http.HandleFunc("/bad_5", func(w http.ResponseWriter, req *http.Request) { + + // BAD: Unicode normalization is performed after the check whether the unicode_input contains an unsafe characters + // "<" and ">". This may be bypassed using the Unicode characters equivalent to "<" and ">". + unicode_input := req.URL.Query().Get("unicode_input") + if strings.Count("<", unicode_input) > 0 || strings.Count(">", unicode_input) > 0 { + fmt.Println("The input is not safe.") + } else { + unicode_norm := norm.NFKC.String(unicode_input) // $result=BAD + fmt.Println(w, "Results: %q", unicode_norm) + } + + }) + +} diff --git a/go/ql/test/experimental/CWE-176/UnicodeBypassValidation.qlref b/go/ql/test/experimental/CWE-176/UnicodeBypassValidation.qlref new file mode 100644 index 000000000000..0488bc8b2a64 --- /dev/null +++ b/go/ql/test/experimental/CWE-176/UnicodeBypassValidation.qlref @@ -0,0 +1 @@ +experimental/CWE-176/UnicodeBypassValidation.ql diff --git a/go/ql/test/experimental/CWE-176/go.mod b/go/ql/test/experimental/CWE-176/go.mod new file mode 100644 index 000000000000..d3ce8ae30bc1 --- /dev/null +++ b/go/ql/test/experimental/CWE-176/go.mod @@ -0,0 +1,5 @@ +module main + +go 1.20 + +require golang.org/x/text v0.9.0 diff --git a/go/ql/test/experimental/CWE-176/vendor/golang.org/x/text/LICENSE b/go/ql/test/experimental/CWE-176/vendor/golang.org/x/text/LICENSE new file mode 100644 index 000000000000..6a66aea5eafe --- /dev/null +++ b/go/ql/test/experimental/CWE-176/vendor/golang.org/x/text/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/go/ql/test/experimental/CWE-176/vendor/golang.org/x/text/PATENTS b/go/ql/test/experimental/CWE-176/vendor/golang.org/x/text/PATENTS new file mode 100644 index 000000000000..733099041f84 --- /dev/null +++ b/go/ql/test/experimental/CWE-176/vendor/golang.org/x/text/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/go/ql/test/experimental/CWE-176/vendor/golang.org/x/text/unicode/norm/normalize.go b/go/ql/test/experimental/CWE-176/vendor/golang.org/x/text/unicode/norm/normalize.go new file mode 100644 index 000000000000..a6cfe72443a3 --- /dev/null +++ b/go/ql/test/experimental/CWE-176/vendor/golang.org/x/text/unicode/norm/normalize.go @@ -0,0 +1,37 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package norm contains types and functions for normalizing Unicode strings. +package norm // import "golang.org/x/text/unicode/norm" + +// A Form denotes a canonical representation of Unicode code points. +// The Unicode-defined normalization and equivalence forms are: +// +// NFC Unicode Normalization Form C +// NFD Unicode Normalization Form D +// NFKC Unicode Normalization Form KC +// NFKD Unicode Normalization Form KD +// +// For a Form f, this documentation uses the notation f(x) to mean +// the bytes or string x converted to the given form. +// A position n in x is called a boundary if conversion to the form can +// proceed independently on both sides: +// +// f(x) == append(f(x[0:n]), f(x[n:])...) +// +// References: https://unicode.org/reports/tr15/ and +// https://unicode.org/notes/tn5/. +type Form int + +const ( + NFC Form = iota + NFD + NFKC + NFKD +) + +// String returns f(s). +func (f Form) String(s string) string { + return "" +} diff --git a/go/ql/test/experimental/CWE-176/vendor/modules.txt b/go/ql/test/experimental/CWE-176/vendor/modules.txt new file mode 100644 index 000000000000..a9c7845cc17a --- /dev/null +++ b/go/ql/test/experimental/CWE-176/vendor/modules.txt @@ -0,0 +1,3 @@ +# golang.org/x/text v0.9.0 +## explicit; go 1.17 +golang.org/x/text/unicode/norm