Skip to content

Commit ba37e8e

Browse files
authored
.Net: Add backslash escaping to redis text search values (#13902)
### Motivation and Context ### Description - Add backslash escaping to redis text search values ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [ ] The code builds clean without any errors or warnings - [ ] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [ ] All unit tests pass, and I have added new tests where possible - [ ] I didn't break anyone 😄
1 parent bf1b19c commit ba37e8e

2 files changed

Lines changed: 54 additions & 2 deletions

File tree

dotnet/src/VectorData/Redis/RedisFilterTranslator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,8 @@ private void TranslateAny(Expression source, LambdaExpression lambda)
258258

259259
private static string SanitizeStringConstant(string value)
260260
#if NET
261-
=> value.Replace("\"", "\\\"", StringComparison.Ordinal);
261+
=> value.Replace("\\", "\\\\", StringComparison.Ordinal).Replace("\"", "\\\"", StringComparison.Ordinal);
262262
#else
263-
=> value.Replace("\"", "\\\"");
263+
=> value.Replace("\\", "\\\\").Replace("\"", "\\\"");
264264
#endif
265265
}

dotnet/test/VectorData/Redis.UnitTests/RedisFilterTranslatorTests.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,58 @@ public void Equal_with_double_quote_in_value()
108108
Assert.Equal("""@Name:{"foo\"bar"}""", result);
109109
}
110110

111+
[Fact]
112+
public void Equal_with_backslash_in_value()
113+
{
114+
var result = Translate<TestRecord>(r => r.Name == "foo\\bar");
115+
Assert.Equal("""@Name:{"foo\\bar"}""", result);
116+
}
117+
118+
[Fact]
119+
public void Equal_with_single_backslash()
120+
{
121+
var result = Translate<TestRecord>(r => r.Name == "\\");
122+
Assert.Equal("""@Name:{"\\"}""", result);
123+
}
124+
125+
[Fact]
126+
public void Equal_with_backslash_quote_injection_attempt()
127+
{
128+
// Input: \" which should NOT break out of the quoted string
129+
var result = Translate<TestRecord>(r => r.Name == "\\\"");
130+
Assert.Equal("""@Name:{"\\\""}""", result);
131+
}
132+
133+
[Fact]
134+
public void Equal_with_backslash_quote_wildcard_injection()
135+
{
136+
// The specific attack payload: \" | * | \"
137+
var result = Translate<TestRecord>(r => r.Name == "\\\" | * | \\\"");
138+
Assert.Equal("""@Name:{"\\\" | * | \\\""}""", result);
139+
}
140+
141+
[Fact]
142+
public void Contains_with_backslash_in_value()
143+
{
144+
var result = Translate<TestRecord>(r => r.Tags.Contains("foo\\bar"));
145+
Assert.Equal("""@Tags:{"foo\\bar"}""", result);
146+
}
147+
148+
[Fact]
149+
public void Contains_with_backslash_quote_injection_attempt()
150+
{
151+
var result = Translate<TestRecord>(r => r.Tags.Contains("\\\""));
152+
Assert.Equal("""@Tags:{"\\\""}""", result);
153+
}
154+
155+
[Fact]
156+
public void Any_with_backslash_in_values()
157+
{
158+
var values = new[] { "a\\b", "c\\d" };
159+
var result = Translate<TestRecord>(r => r.Tags.Any(t => values.Contains(t)));
160+
Assert.Equal("""@Tags:{"a\\b" | "c\\d"}""", result);
161+
}
162+
111163
private static string Translate<TRecord>(Expression<Func<TRecord, bool>> filter)
112164
{
113165
var model = BuildModel();

0 commit comments

Comments
 (0)