diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5141e8016..b3b0e9b90 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,6 +6,10 @@ updates: schedule: # Check for updates to GitHub Actions every quarter interval: "quarterly" + # Wait a few days after a release before opening an update PR, to avoid + # picking up versions that are pulled shortly after publishing. + cooldown: + default-days: 7 labels: - "Release Not Needed" target-branch: "dev" diff --git a/.semgrepignore b/.semgrepignore index 5a02b9ea5..d820d0511 100644 --- a/.semgrepignore +++ b/.semgrepignore @@ -7,6 +7,14 @@ **/*.min.js **/env.configs.yml +# Ignore the ASP.NET integration-test host app. Its controllers are intentionally +# unauthenticated fixtures used to exercise the Lambda bridge and are never shipped. +**/test/TestWebApp/** + +# Ignore the v1 (preview) test tool's Blazor debug UI. It intentionally shows the +# developer exception page since its purpose is local debugging of Lambda code. +**/Amazon.Lambda.TestTool.BlazorTester/** + # Ignore third-party libraries **/node_modules/** **/vendor/** diff --git a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Services/LambdaRequestManager.cs b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Services/LambdaRequestManager.cs index 9386a82e4..1878fe233 100644 --- a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Services/LambdaRequestManager.cs +++ b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Services/LambdaRequestManager.cs @@ -82,10 +82,11 @@ public string GetRequest(string functionName, string requestName) if (requestDirectory is null) return string.Empty; - if(requestName.StartsWith(Constants.SavedRequestDirectory + "@")) + if(requestName.StartsWith(Constants.SavedRequestDirectory + "@", StringComparison.Ordinal)) { requestName = requestName.Substring(requestName.IndexOf("@", StringComparison.Ordinal) + 1); - var path = Path.Combine(requestDirectory, requestName); + // Use only the file name so a crafted request name cannot escape requestDirectory. + var path = Path.Combine(requestDirectory, Path.GetFileName(requestName)); return File.ReadAllText(path); } return GetEmbeddedResource(requestName); diff --git a/Tools/LambdaTestTool/src/Amazon.Lambda.TestTool/SampleRequests/SampleRequestManager.cs b/Tools/LambdaTestTool/src/Amazon.Lambda.TestTool/SampleRequests/SampleRequestManager.cs index c7f978d97..c6edfad07 100644 --- a/Tools/LambdaTestTool/src/Amazon.Lambda.TestTool/SampleRequests/SampleRequestManager.cs +++ b/Tools/LambdaTestTool/src/Amazon.Lambda.TestTool/SampleRequests/SampleRequestManager.cs @@ -99,10 +99,11 @@ public static bool TryDetermineSampleRequestName(string value, out string sample public string GetRequest(string name) { - if(name.StartsWith(SAVED_REQUEST_DIRECTORY + "@")) + if(name.StartsWith(SAVED_REQUEST_DIRECTORY + "@", StringComparison.Ordinal)) { - name = name.Substring(name.IndexOf("@") + 1); - var path = Path.Combine(this.GetSavedRequestDirectory(), name); + name = name.Substring(name.IndexOf('@') + 1); + // Use only the file name so a crafted request name cannot escape the saved-request directory. + var path = Path.Combine(this.GetSavedRequestDirectory(), Path.GetFileName(name)); return File.ReadAllText(path); } return GetEmbeddedResource(name); diff --git a/Tools/LambdaTestTool/tests/Amazon.Lambda.TestTool.Tests/SampleRequestTests.cs b/Tools/LambdaTestTool/tests/Amazon.Lambda.TestTool.Tests/SampleRequestTests.cs index 41d7e1d15..2197de07a 100644 --- a/Tools/LambdaTestTool/tests/Amazon.Lambda.TestTool.Tests/SampleRequestTests.cs +++ b/Tools/LambdaTestTool/tests/Amazon.Lambda.TestTool.Tests/SampleRequestTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Text; using Xunit; @@ -26,5 +27,28 @@ public void DetermineSampleName(string testValue, string expected) Assert.Null(expected); } } + + [Fact] + public void GetRequest_WithTraversalName_StaysWithinSavedRequestDirectory() + { + var preferenceDirectory = Path.Combine(Path.GetTempPath(), "LambdaTestToolTests", Guid.NewGuid().ToString()); + var savedRequestDirectory = Path.Combine(preferenceDirectory, SampleRequestManager.SAVED_REQUEST_DIRECTORY); + Directory.CreateDirectory(savedRequestDirectory); + try + { + File.WriteAllText(Path.Combine(savedRequestDirectory, "target.json"), "INSIDE"); + File.WriteAllText(Path.Combine(preferenceDirectory, "target.json"), "OUTSIDE"); + + var manager = new SampleRequestManager(preferenceDirectory); + + var content = manager.GetRequest($"{SampleRequestManager.SAVED_REQUEST_DIRECTORY}@../target.json"); + + Assert.Equal("INSIDE", content); + } + finally + { + Directory.Delete(preferenceDirectory, recursive: true); + } + } } }