diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index e400278..393d187 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -8,13 +8,6 @@ "dotnet-csharpier" ], "rollForward": false - }, - "dotnet-ef": { - "version": "9.0.2", - "commands": [ - "dotnet-ef" - ], - "rollForward": false } } } \ No newline at end of file diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 2a5be5b..115c73d 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -25,6 +25,8 @@ concurrency: jobs: build-and-test: runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@v4 @@ -52,6 +54,9 @@ jobs: needs: build-and-test if: github.event_name == 'release' runs-on: ubuntu-latest + permissions: + contents: read + packages: write steps: - uses: actions/checkout@v4 diff --git a/JsonApiToolkit/Extensions/Querying/Filtering/NestedPropertyNavigator.cs b/JsonApiToolkit/Extensions/Querying/Filtering/NestedPropertyNavigator.cs index 3b5a29e..1768fd9 100644 --- a/JsonApiToolkit/Extensions/Querying/Filtering/NestedPropertyNavigator.cs +++ b/JsonApiToolkit/Extensions/Querying/Filtering/NestedPropertyNavigator.cs @@ -1,12 +1,37 @@ using System.Linq.Expressions; using System.Reflection; +using System.Text.RegularExpressions; using JsonApiToolkit.Models.Querying.Filtering; using Microsoft.Extensions.Logging; namespace JsonApiToolkit.Extensions.Querying; -internal static class NestedPropertyNavigator +internal static partial class NestedPropertyNavigator { + private const int MaxLogValueLength = 100; + + /// + /// Sanitizes user input for safe logging by removing control characters + /// and truncating long values to prevent log forging attacks. + /// + private static string SanitizeForLog(string? value) + { + if (string.IsNullOrEmpty(value)) + return "(empty)"; + + // Remove control characters (newlines, tabs, etc.) that could forge log entries + string sanitized = ControlCharRegex().Replace(value, " "); + + // Truncate long values + if (sanitized.Length > MaxLogValueLength) + return string.Concat(sanitized.AsSpan(0, MaxLogValueLength), "...(truncated)"); + + return sanitized; + } + + [GeneratedRegex(@"[\x00-\x1F\x7F]")] + private static partial Regex ControlCharRegex(); + internal static Expression? BuildSafeNestedFilterExpression( ParameterExpression parameter, FilterParameter filter, @@ -268,7 +293,7 @@ internal static class NestedPropertyNavigator { logger?.LogWarning( "Failed to convert '{Value}' to {ElementType} for collection filter", - filter.Value, + SanitizeForLog(filter.Value), elementType.Name ); return null; @@ -295,7 +320,7 @@ internal static class NestedPropertyNavigator { logger?.LogWarning( "Failed to convert '{Value}' to {ElementType} for collection filter", - filter.Value, + SanitizeForLog(filter.Value), elementType.Name ); return null; @@ -412,7 +437,7 @@ internal static class NestedPropertyNavigator { logger?.LogWarning( "Failed to convert '{Value}' to {PropertyType}", - filter.Value, + SanitizeForLog(filter.Value), targetType.Name ); return null;