From 92198e1af0ddb3525192dc666d873e149ac2498a Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Fri, 24 Mar 2023 14:09:06 +0000 Subject: [PATCH 1/9] Add local file writes as external location sinks --- .../flowsinks/ExternalLocationSink.qll | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll index 30736bdabf65..0f8b7551b280 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll @@ -6,7 +6,9 @@ import csharp private import Remote private import semmle.code.csharp.commons.Loggers private import semmle.code.csharp.frameworks.system.Web +private import semmle.code.csharp.frameworks.system.IO private import semmle.code.csharp.dataflow.ExternalFlow +private import semmle.code.csharp.dataflow.DataFlow /** * An external location sink. @@ -63,3 +65,66 @@ class CookieStorageSink extends ExternalLocationSink, RemoteFlowSink { ) } } + +private predicate isFileWriteCall(Expr stream, Expr data) { + exists(MethodCall mc, Method m | mc.getTarget() = m.getAnOverrider*() | + mc.getTarget().hasQualifiedName("System.IO", "Stream", ["Write", "WriteAsync"]) and + stream = mc.getQualifier() and + data = mc.getArgument(0) + or + mc.getTarget() + .hasQualifiedName("System.IO", "TextWriter", + ["Write", "WriteAsync", "WriteLine", "WriteLineAsync"]) and + stream = mc.getQualifier() and + data = mc.getArgument(0) + or + mc.getTarget().hasQualifiedName("System.Xml.Linq", "XDocument", ["Save", "SaveAsync"]) and + data = mc.getQualifier() and + stream = mc.getArgument(0) + ) +} + +private module LocalFileOutputStreamConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node src) { + exists(MethodCall mc | mc = src.asExpr() | + mc.getTarget().hasQualifiedName("System.IO", "File", ["Open", "Create", "OpenWrite"]) + or + mc.getTarget() + .hasQualifiedName("System.IO", "FileInfo", + ["AppendText", "Create", "CreateText", "Open", "OpenText", "OpenWrite"]) + ) + or + exists(ObjectCreation oc | oc = src.asExpr() | + oc.getObjectType() instanceof SystemIOStreamWriterClass and + oc.getArgument(0).getType() instanceof StringType + ) + } + + predicate isSink(DataFlow::Node sink) { isFileWriteCall(sink.asExpr(), _) } + + predicate isBarrier(DataFlow::Node node) { + node.asExpr() + .(ObjectCreation) + .getObjectType() + .hasQualifiedName("System.Security.Cryptography", "CryptoStream") + } + + predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ObjectCreation oc | + node2.asExpr() = oc and + node1.asExpr() = oc.getArgument(0) and + oc.getObjectType() instanceof SystemIOStreamWriterClass + ) + } +} + +private module LocalFileOutputStreamFlow = DataFlow::Make; + +class LocalFileOutputSink extends ExternalLocationSink { + LocalFileOutputSink() { + exists(DataFlow::Node streamSink | + LocalFileOutputStreamFlow::hasFlow(_, streamSink) and + isFileWriteCall(streamSink.asExpr(), this.asExpr()) + ) + } +} From cb2b2bc334c7448363477531ad13bd8a8ed489e5 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Mon, 27 Mar 2023 16:07:29 +0100 Subject: [PATCH 2/9] Add qldoc and remove redundant import --- .../security/dataflow/flowsinks/ExternalLocationSink.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll index 0f8b7551b280..511d0ba2ebb3 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll @@ -8,7 +8,6 @@ private import semmle.code.csharp.commons.Loggers private import semmle.code.csharp.frameworks.system.Web private import semmle.code.csharp.frameworks.system.IO private import semmle.code.csharp.dataflow.ExternalFlow -private import semmle.code.csharp.dataflow.DataFlow /** * An external location sink. @@ -120,6 +119,9 @@ private module LocalFileOutputStreamConfig implements DataFlow::ConfigSig { private module LocalFileOutputStreamFlow = DataFlow::Make; +/** + * A write to the local filesystem. + */ class LocalFileOutputSink extends ExternalLocationSink { LocalFileOutputSink() { exists(DataFlow::Node streamSink | From 941df4f2748eb29a7df376dbdf2c62af24d0db66 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Wed, 5 Apr 2023 11:10:32 +0100 Subject: [PATCH 3/9] Add test for cleartext storage --- .../flowsinks/ExternalLocationSink.qll | 12 ++++--- .../CWE-312/CleartextStorage.cs | 22 ++++++++++++ .../CWE-312/CleartextStorage.expected | 34 ++++++++++--------- .../Security Features/CWE-312/options | 2 +- 4 files changed, 48 insertions(+), 22 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll index 511d0ba2ebb3..d6d9a9157161 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll @@ -65,19 +65,21 @@ class CookieStorageSink extends ExternalLocationSink, RemoteFlowSink { } } + + private predicate isFileWriteCall(Expr stream, Expr data) { exists(MethodCall mc, Method m | mc.getTarget() = m.getAnOverrider*() | - mc.getTarget().hasQualifiedName("System.IO", "Stream", ["Write", "WriteAsync"]) and + m.hasQualifiedName("System.IO", "Stream", ["Write", "WriteAsync"]) and stream = mc.getQualifier() and data = mc.getArgument(0) or - mc.getTarget() + m .hasQualifiedName("System.IO", "TextWriter", ["Write", "WriteAsync", "WriteLine", "WriteLineAsync"]) and stream = mc.getQualifier() and data = mc.getArgument(0) or - mc.getTarget().hasQualifiedName("System.Xml.Linq", "XDocument", ["Save", "SaveAsync"]) and + m.hasQualifiedName("System.Xml.Linq", "XDocument", ["Save", "SaveAsync"]) and data = mc.getQualifier() and stream = mc.getArgument(0) ) @@ -117,7 +119,7 @@ private module LocalFileOutputStreamConfig implements DataFlow::ConfigSig { } } -private module LocalFileOutputStreamFlow = DataFlow::Make; +private module LocalFileOutputStreamFlow = DataFlow::Global; /** * A write to the local filesystem. @@ -125,7 +127,7 @@ private module LocalFileOutputStreamFlow = DataFlow::Make Date: Wed, 5 Apr 2023 13:55:48 +0100 Subject: [PATCH 4/9] Add unit tests for private information query --- .../CWE-359/ExposureOfPrivateInformation.cs | 22 +++++++++++++++++++ .../ExposureOfPrivateInformation.expected | 18 ++++++++------- .../Security Features/CWE-359/options | 2 +- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/csharp/ql/test/query-tests/Security Features/CWE-359/ExposureOfPrivateInformation.cs b/csharp/ql/test/query-tests/Security Features/CWE-359/ExposureOfPrivateInformation.cs index f7d0755d65e7..675b05c29de3 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-359/ExposureOfPrivateInformation.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-359/ExposureOfPrivateInformation.cs @@ -1,4 +1,6 @@ using System.Web; +using System.Security.Cryptography; +using System.IO; public class Person { @@ -21,9 +23,29 @@ public void ProcessRequest(HttpContext ctx) ILogger logger = new ILogger(); logger.Warn(p.getTelephone()); + // BAD: Storing sensitive data in unencrypted local file + using (var writeStream = File.Open("telephones.txt", FileMode.Create)) + { + var writer = new StreamWriter(writeStream); + writer.Write(p.getTelephone()); + writer.Close(); + } + + // GOOD: Storing encrypted sensitive data + using (var writeStream = File.Open("telephones.txt", FileMode.Create)) + { + var writer = new StreamWriter(new CryptoStream(writeStream, GetEncryptor(), CryptoStreamMode.Write)); + writer.Write(p.getTelephone()); + writer.Close(); + } + // GOOD: Don't write these values to sensitive locations in the first place } + public ICryptoTransform GetEncryptor(){ + return null; + } + public bool IsReusable { get diff --git a/csharp/ql/test/query-tests/Security Features/CWE-359/ExposureOfPrivateInformation.expected b/csharp/ql/test/query-tests/Security Features/CWE-359/ExposureOfPrivateInformation.expected index d9f5ee50ee15..417692ff79ef 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-359/ExposureOfPrivateInformation.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-359/ExposureOfPrivateInformation.expected @@ -1,12 +1,14 @@ edges nodes -| ExposureOfPrivateInformation.cs:16:50:16:84 | access to indexer | semmle.label | access to indexer | -| ExposureOfPrivateInformation.cs:18:50:18:65 | call to method getTelephone | semmle.label | call to method getTelephone | -| ExposureOfPrivateInformation.cs:22:21:22:36 | call to method getTelephone | semmle.label | call to method getTelephone | -| ExposureOfPrivateInformation.cs:40:21:40:33 | access to property Text | semmle.label | access to property Text | +| ExposureOfPrivateInformation.cs:18:50:18:84 | access to indexer | semmle.label | access to indexer | +| ExposureOfPrivateInformation.cs:20:50:20:65 | call to method getTelephone | semmle.label | call to method getTelephone | +| ExposureOfPrivateInformation.cs:24:21:24:36 | call to method getTelephone | semmle.label | call to method getTelephone | +| ExposureOfPrivateInformation.cs:30:26:30:41 | call to method getTelephone | semmle.label | call to method getTelephone | +| ExposureOfPrivateInformation.cs:62:21:62:33 | access to property Text | semmle.label | access to property Text | subpaths #select -| ExposureOfPrivateInformation.cs:16:50:16:84 | access to indexer | ExposureOfPrivateInformation.cs:16:50:16:84 | access to indexer | ExposureOfPrivateInformation.cs:16:50:16:84 | access to indexer | Private data returned by $@ is written to an external location. | ExposureOfPrivateInformation.cs:16:50:16:84 | access to indexer | access to indexer | -| ExposureOfPrivateInformation.cs:18:50:18:65 | call to method getTelephone | ExposureOfPrivateInformation.cs:18:50:18:65 | call to method getTelephone | ExposureOfPrivateInformation.cs:18:50:18:65 | call to method getTelephone | Private data returned by $@ is written to an external location. | ExposureOfPrivateInformation.cs:18:50:18:65 | call to method getTelephone | call to method getTelephone | -| ExposureOfPrivateInformation.cs:22:21:22:36 | call to method getTelephone | ExposureOfPrivateInformation.cs:22:21:22:36 | call to method getTelephone | ExposureOfPrivateInformation.cs:22:21:22:36 | call to method getTelephone | Private data returned by $@ is written to an external location. | ExposureOfPrivateInformation.cs:22:21:22:36 | call to method getTelephone | call to method getTelephone | -| ExposureOfPrivateInformation.cs:40:21:40:33 | access to property Text | ExposureOfPrivateInformation.cs:40:21:40:33 | access to property Text | ExposureOfPrivateInformation.cs:40:21:40:33 | access to property Text | Private data returned by $@ is written to an external location. | ExposureOfPrivateInformation.cs:40:21:40:33 | access to property Text | access to property Text | +| ExposureOfPrivateInformation.cs:18:50:18:84 | access to indexer | ExposureOfPrivateInformation.cs:18:50:18:84 | access to indexer | ExposureOfPrivateInformation.cs:18:50:18:84 | access to indexer | Private data returned by $@ is written to an external location. | ExposureOfPrivateInformation.cs:18:50:18:84 | access to indexer | access to indexer | +| ExposureOfPrivateInformation.cs:20:50:20:65 | call to method getTelephone | ExposureOfPrivateInformation.cs:20:50:20:65 | call to method getTelephone | ExposureOfPrivateInformation.cs:20:50:20:65 | call to method getTelephone | Private data returned by $@ is written to an external location. | ExposureOfPrivateInformation.cs:20:50:20:65 | call to method getTelephone | call to method getTelephone | +| ExposureOfPrivateInformation.cs:24:21:24:36 | call to method getTelephone | ExposureOfPrivateInformation.cs:24:21:24:36 | call to method getTelephone | ExposureOfPrivateInformation.cs:24:21:24:36 | call to method getTelephone | Private data returned by $@ is written to an external location. | ExposureOfPrivateInformation.cs:24:21:24:36 | call to method getTelephone | call to method getTelephone | +| ExposureOfPrivateInformation.cs:30:26:30:41 | call to method getTelephone | ExposureOfPrivateInformation.cs:30:26:30:41 | call to method getTelephone | ExposureOfPrivateInformation.cs:30:26:30:41 | call to method getTelephone | Private data returned by $@ is written to an external location. | ExposureOfPrivateInformation.cs:30:26:30:41 | call to method getTelephone | call to method getTelephone | +| ExposureOfPrivateInformation.cs:62:21:62:33 | access to property Text | ExposureOfPrivateInformation.cs:62:21:62:33 | access to property Text | ExposureOfPrivateInformation.cs:62:21:62:33 | access to property Text | Private data returned by $@ is written to an external location. | ExposureOfPrivateInformation.cs:62:21:62:33 | access to property Text | access to property Text | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-359/options b/csharp/ql/test/query-tests/Security Features/CWE-359/options index 35e6ec9b23f1..aa088071c5db 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-359/options +++ b/csharp/ql/test/query-tests/Security Features/CWE-359/options @@ -1 +1 @@ -semmle-extractor-options: ${testdir}/../../../resources/stubs/System.Web.cs /r:System.Collections.Specialized.dll ${testdir}/../../../resources/stubs/System.Windows.cs +semmle-extractor-options: ${testdir}/../../../resources/stubs/System.Web.cs /r:System.Collections.Specialized.dll /r:System.Security.Cryptography.dll ${testdir}/../../../resources/stubs/System.Windows.cs From 8b08e6042c2dd132c3f97359fc485f66bad3dd8d Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Wed, 5 Apr 2023 14:22:55 +0100 Subject: [PATCH 5/9] Update formatting --- .../security/dataflow/flowsinks/ExternalLocationSink.qll | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll index d6d9a9157161..4e8efcc612c1 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll @@ -65,17 +65,14 @@ class CookieStorageSink extends ExternalLocationSink, RemoteFlowSink { } } - - private predicate isFileWriteCall(Expr stream, Expr data) { exists(MethodCall mc, Method m | mc.getTarget() = m.getAnOverrider*() | m.hasQualifiedName("System.IO", "Stream", ["Write", "WriteAsync"]) and stream = mc.getQualifier() and data = mc.getArgument(0) or - m - .hasQualifiedName("System.IO", "TextWriter", - ["Write", "WriteAsync", "WriteLine", "WriteLineAsync"]) and + m.hasQualifiedName("System.IO", "TextWriter", + ["Write", "WriteAsync", "WriteLine", "WriteLineAsync"]) and stream = mc.getQualifier() and data = mc.getArgument(0) or From 17cfd489ea029b7ff78984f8b7065e4686ec2db5 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Wed, 5 Apr 2023 14:28:49 +0100 Subject: [PATCH 6/9] Add change note --- .../ql/src/change-notes/2023-04-05-external-location-sinks.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/src/change-notes/2023-04-05-external-location-sinks.md diff --git a/csharp/ql/src/change-notes/2023-04-05-external-location-sinks.md b/csharp/ql/src/change-notes/2023-04-05-external-location-sinks.md new file mode 100644 index 000000000000..e306794f6577 --- /dev/null +++ b/csharp/ql/src/change-notes/2023-04-05-external-location-sinks.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Additional sinks modelling writes to unencrypted local files have been added to `ExternalLocationSink`, used by the `cs/cleartext-storage` and `cs/exposure-of-sensitive-information` queries. \ No newline at end of file From 9881fdfe2720dea0579f2e1539c9bd4a53453098 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Fri, 21 Apr 2023 14:19:17 +0100 Subject: [PATCH 7/9] Convert sources to MaD --- csharp/ql/lib/ext/System.IO.model.yml | 10 ++++++++++ .../semmle/code/csharp/dataflow/ExternalFlow.qll | 2 +- .../dataflow/flowsinks/ExternalLocationSink.qll | 15 +-------------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/csharp/ql/lib/ext/System.IO.model.yml b/csharp/ql/lib/ext/System.IO.model.yml index 49b0818ef5f0..55c91fff30e7 100644 --- a/csharp/ql/lib/ext/System.IO.model.yml +++ b/csharp/ql/lib/ext/System.IO.model.yml @@ -4,6 +4,16 @@ extensions: extensible: sourceModel data: - ["System.IO", "FileStream", False, "FileStream", "", "", "Argument[this]", "file", "manual"] + - ["System.IO", "FileStream", False, "FileStream", "", "", "Argument[this]", "file-write", "manual"] + - ["System.IO", "StreamWriter", False, "StreamWriter", "(System.String)", "", "Argument[this]", "file-write", "manual"] + - ["System.IO", "StreamWriter", False, "StreamWriter", "(System.String,System.Boolean)", "", "Argument[this]", "file-write", "manual"] + - ["System.IO", "StreamWriter", False, "StreamWriter", "(System.String,System.Boolean,System.Text.Encoding)", "", "Argument[this]", "file-write", "manual"] + - ["System.IO", "StreamWriter", False, "StreamWriter", "(System.String,System.Boolean,System.Text.Encoding,System.Int32)", "", "Argument[this]", "file-write", "manual"] + - ["System.IO", "StreamWriter", False, "StreamWriter", "(System.String,System.Text.Encoding,System.IO.FileStreamOptions)", "", "Argument[this]", "file-write", "manual"] + - ["System.IO", "StreamWriter", False, "StreamWriter", "(System.String,System.IO.FileStreamOptions)", "", "Argument[this]", "file-write", "manual"] + - ["System.IO", "File", False, "Open", "", "", "ReturnValue", "file-write", "manual"] + - ["System.IO", "File", False, "OpenWrite", "", "", "ReturnValue", "file-write", "manual"] + - ["System.IO", "File", False, "Create", "", "", "ReturnValue", "file-write", "manual"] - addsTo: pack: codeql/csharp-all extensible: summaryModel diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 2792c1d180c6..f139fb54da8f 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -212,7 +212,7 @@ module ModelValidation { ) or exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | - not kind = ["local", "remote", "file"] and + not kind = ["local", "remote", "file", "file-write"] and result = "Invalid kind \"" + kind + "\" in source model." ) } diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll index 4e8efcc612c1..a3350b0b57e7 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll @@ -83,20 +83,7 @@ private predicate isFileWriteCall(Expr stream, Expr data) { } private module LocalFileOutputStreamConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node src) { - exists(MethodCall mc | mc = src.asExpr() | - mc.getTarget().hasQualifiedName("System.IO", "File", ["Open", "Create", "OpenWrite"]) - or - mc.getTarget() - .hasQualifiedName("System.IO", "FileInfo", - ["AppendText", "Create", "CreateText", "Open", "OpenText", "OpenWrite"]) - ) - or - exists(ObjectCreation oc | oc = src.asExpr() | - oc.getObjectType() instanceof SystemIOStreamWriterClass and - oc.getArgument(0).getType() instanceof StringType - ) - } + predicate isSource(DataFlow::Node src) { sourceNode(src, "file-write") } predicate isSink(DataFlow::Node sink) { isFileWriteCall(sink.asExpr(), _) } From a4d75707886fab85882e3ae94935e181254266ae Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Fri, 21 Apr 2023 14:23:01 +0100 Subject: [PATCH 8/9] Add more sources --- csharp/ql/lib/ext/System.IO.model.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/csharp/ql/lib/ext/System.IO.model.yml b/csharp/ql/lib/ext/System.IO.model.yml index 55c91fff30e7..8222f51d624a 100644 --- a/csharp/ql/lib/ext/System.IO.model.yml +++ b/csharp/ql/lib/ext/System.IO.model.yml @@ -14,6 +14,13 @@ extensions: - ["System.IO", "File", False, "Open", "", "", "ReturnValue", "file-write", "manual"] - ["System.IO", "File", False, "OpenWrite", "", "", "ReturnValue", "file-write", "manual"] - ["System.IO", "File", False, "Create", "", "", "ReturnValue", "file-write", "manual"] + - ["System.IO", "File", False, "CreateText", "", "", "ReturnValue", "file-write", "manual"] + - ["System.IO", "File", False, "AppendText", "", "", "ReturnValue", "file-write", "manual"] + - ["System.IO", "FileInfo", False, "Open", "", "", "ReturnValue", "file-write", "manual"] + - ["System.IO", "FileInfo", False, "OpenWrite", "", "", "ReturnValue", "file-write", "manual"] + - ["System.IO", "FileInfo", False, "Create", "", "", "ReturnValue", "file-write", "manual"] + - ["System.IO", "FileInfo", False, "CreateText", "", "", "ReturnValue", "file-write", "manual"] + - ["System.IO", "FileInfo", False, "AppendText", "", "", "ReturnValue", "file-write", "manual"] - addsTo: pack: codeql/csharp-all extensible: summaryModel From 0ebf529dc420c57049a7c3ef2bb1e4c6819de02b Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Mon, 24 Apr 2023 15:49:05 +0100 Subject: [PATCH 9/9] Add comment + use flowTo --- .../security/dataflow/flowsinks/ExternalLocationSink.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll index a3350b0b57e7..26b75f06269c 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll @@ -82,6 +82,7 @@ private predicate isFileWriteCall(Expr stream, Expr data) { ) } +/** A configuration for tracking flow from calls that open a file in write mode to methods that write to that file, excluding encrypted streams. */ private module LocalFileOutputStreamConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node src) { sourceNode(src, "file-write") } @@ -111,7 +112,7 @@ private module LocalFileOutputStreamFlow = DataFlow::Global