Skip to content

Commit df48fc7

Browse files
committed
Throw exception on unescaped equals sign
Unescaped equals sign in extension values should be rejected. CEF v27 spec as well as beats impl does this
1 parent 3f7c3d4 commit df48fc7

File tree

2 files changed

+36
-74
lines changed

2 files changed

+36
-74
lines changed

modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/CefParser.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ enum DataType {
283283

284284
private static final String INCOMPLETE_CEF_HEADER = "Incomplete CEF header";
285285
private static final String INVALID_CEF_FORMAT = "Invalid CEF format";
286+
private static final String UNESCAPED_EQUALS_SIGN = "CEF extensions contain unescaped equals sign";
286287

287288
/**
288289
* List of allowed timestamp formats for CEF spec v27, see: Appendix A: Date Formats
@@ -416,6 +417,9 @@ private static Map<String, String> parseExtensions(String extensionString) {
416417
if (i == allMatches.size() - 1) {
417418
value = value.trim();
418419
}
420+
if (hasUnescapedEquals(value)) {
421+
throw new IllegalArgumentException(UNESCAPED_EQUALS_SIGN);
422+
}
419423
extensions.put(key, desanitizeExtensionVal(value));
420424
lastEnd = match.end();
421425
}
@@ -426,6 +430,32 @@ private static Map<String, String> parseExtensions(String extensionString) {
426430
return extensions;
427431
}
428432

433+
private static boolean hasUnescapedEquals(String value) {
434+
if (value == null || value.isEmpty()) {
435+
return false; // Empty or null strings have no unescaped equals signs
436+
}
437+
438+
// If there are no equals signs at all, return false
439+
if (value.indexOf('=') < 0) {
440+
return false;
441+
}
442+
443+
boolean escaped = true;
444+
for (int i = 0; i < value.length(); i++) {
445+
char c = value.charAt(i);
446+
447+
if (escaped == false) {
448+
escaped = true; // Reset escape flag after processing an escaped character
449+
} else if (c == '\\') {
450+
escaped = false; // Set escape flag when a backslash is encountered
451+
} else if (c == '=') {
452+
return true; // Found an unescaped equals sign, so return immediately
453+
}
454+
}
455+
// If we get here without finding an unescaped equals sign, return false
456+
return false;
457+
}
458+
429459
private Object convertValueToType(String value, DataType type) {
430460
return switch (type) {
431461
case StringType -> value;

modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/CefProcessorTests.java

Lines changed: 6 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -344,30 +344,8 @@ public void testEqualsInMessage() {
344344
source.put("message", message);
345345
document = new IngestDocument("index", "id", 1L, null, null, source);
346346
CefProcessor processor = new CefProcessor("tag", "description", "message", "cef", false, true, null);
347-
processor.execute(document);
348-
assertMapsEqual(
349-
document.getSource(),
350-
Map.ofEntries(
351-
entry(
352-
"cef",
353-
Map.ofEntries(
354-
entry("version", "0"),
355-
entry(
356-
"device",
357-
Map.of("vendor", "security", "product", "threatmanager", "version", "1.0", "event_class_id", "100")
358-
),
359-
entry("name", "trojan successfully stopped"),
360-
entry("severity", "10"),
361-
entry("extensions", Map.of("moo", "this =has = equals="))
362-
)
363-
),
364-
entry("event", Map.of("code", "100")),
365-
entry("observer", Map.of("product", "threatmanager", "vendor", "security", "version", "1.0")),
366-
entry("destination", Map.of("ip", "12.121.122.82")),
367-
entry("source", Map.of("port", 1232)),
368-
entry("message", message)
369-
)
370-
);
347+
Exception e = expectThrows(IllegalArgumentException.class, () -> processor.execute(document));
348+
assertThat(e.getMessage(), equalTo("CEF extensions contain unescaped equals sign"));
371349
}
372350

373351
public void testEscapesInExtension() {
@@ -408,34 +386,8 @@ public void testMalformedExtensionEscape() {
408386
source.put("message", message);
409387
document = new IngestDocument("index", "id", 1L, null, null, source);
410388
CefProcessor processor = new CefProcessor("tag", "description", "message", "cef", false, true, null);
411-
processor.execute(document);
412-
assertMapsEqual(
413-
document.getSource(),
414-
Map.ofEntries(
415-
entry(
416-
"cef",
417-
Map.ofEntries(
418-
entry("version", "0"),
419-
entry(
420-
"device",
421-
Map.of("vendor", "FooBar", "product", "Web Gateway", "version", "1.2.3.45.67", "event_class_id", "200")
422-
),
423-
entry("name", "Success"),
424-
entry("severity", "2"),
425-
entry("extensions", Map.of("deviceCustomString1Label", "Foo Bar", "deviceEventCategory", "Access Log"))
426-
)
427-
),
428-
entry("event", Map.of("code", "200")),
429-
entry("observer", Map.of("product", "Web Gateway", "vendor", "FooBar", "version", "1.2.3.45.67")),
430-
entry("@timestamp", ZonedDateTime.parse("2018-09-07T14:50:39Z")),
431-
entry("destination", Map.of("ip", "1.1.1.1", "domain", "foo.example.com")),
432-
entry("source", Map.of("ip", "2.2.2.2", "user", Map.of("name", "redacted"))),
433-
entry("http", Map.of("request", Map.of("method", "POST"))),
434-
entry("url", Map.of("original", "'https://foo.example.com/bar/bingo/1'")),
435-
entry("user_agent", Map.of("original", "'Foo-Bar/2018.1.7; =Email:[email protected]; Guid:test='")),
436-
entry("message", message)
437-
)
438-
);
389+
Exception e = expectThrows(IllegalArgumentException.class, () -> processor.execute(document));
390+
assertThat(e.getMessage(), equalTo("CEF extensions contain unescaped equals sign"));
439391
}
440392

441393
public void testMultipleMalformedExtensionValues() {
@@ -445,28 +397,8 @@ public void testMultipleMalformedExtensionValues() {
445397
source.put("message", message);
446398
document = new IngestDocument("index", "id", 1L, null, null, source);
447399
CefProcessor processor = new CefProcessor("tag", "description", "message", "cef", false, true, null);
448-
processor.execute(document);
449-
assertMapsEqual(
450-
document.getSource(),
451-
Map.ofEntries(
452-
entry(
453-
"cef",
454-
Map.ofEntries(
455-
entry("version", "0"),
456-
entry(
457-
"device",
458-
Map.of("vendor", "vendor", "product", "product", "version", "version", "event_class_id", "event_id")
459-
),
460-
entry("name", "name"),
461-
entry("severity", "Very-High"),
462-
entry("extensions", Map.of("id", "=old_id", "user", "root", "angle", "106.7<=180", "error", "Failed because"))
463-
)
464-
),
465-
entry("event", Map.of("code", "event_id")),
466-
entry("observer", Map.of("product", "product", "vendor", "vendor", "version", "version")),
467-
entry("message", "Hello World")
468-
)
469-
);
400+
Exception e = expectThrows(IllegalArgumentException.class, () -> processor.execute(document));
401+
assertThat(e.getMessage(), equalTo("CEF extensions contain unescaped equals sign"));
470402
}
471403

472404
public void testPaddedMessage() {

0 commit comments

Comments
 (0)