Skip to content

Commit 9ec7fde

Browse files
sezen-datadogjandro996smolaMariovido
authored
Email HTML Injection detection in IAST (#8205)
* Email Injection detection in IAST --------- Co-authored-by: Alejandro González García <[email protected]> Co-authored-by: Santiago M. Mola <[email protected]> Co-authored-by: Mario Vidal Domínguez <[email protected]>
1 parent 41a2e99 commit 9ec7fde

File tree

32 files changed

+885
-16
lines changed

32 files changed

+885
-16
lines changed

dd-java-agent/agent-iast/src/main/java/com/datadog/iast/IastSystem.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.datadog.iast.securitycontrol.IastSecurityControlTransformer;
1212
import com.datadog.iast.sink.ApplicationModuleImpl;
1313
import com.datadog.iast.sink.CommandInjectionModuleImpl;
14+
import com.datadog.iast.sink.EmailInjectionModuleImpl;
1415
import com.datadog.iast.sink.HardcodedSecretModuleImpl;
1516
import com.datadog.iast.sink.HeaderInjectionModuleImpl;
1617
import com.datadog.iast.sink.HstsMissingHeaderModuleImpl;
@@ -179,7 +180,8 @@ private static Stream<IastModule> iastModules(
179180
HardcodedSecretModuleImpl.class,
180181
InsecureAuthProtocolModuleImpl.class,
181182
ReflectionInjectionModuleImpl.class,
182-
UntrustedDeserializationModuleImpl.class);
183+
UntrustedDeserializationModuleImpl.class,
184+
EmailInjectionModuleImpl.class);
183185
if (iast != FULLY_ENABLED) {
184186
modules = modules.filter(IastSystem::isOptOut);
185187
}

dd-java-agent/agent-iast/src/main/java/com/datadog/iast/model/VulnerabilityType.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static com.datadog.iast.util.CRCUtils.update;
44
import static datadog.trace.api.iast.VulnerabilityMarks.COMMAND_INJECTION_MARK;
5+
import static datadog.trace.api.iast.VulnerabilityMarks.EMAIL_HTML_INJECTION_MARK;
56
import static datadog.trace.api.iast.VulnerabilityMarks.HEADER_INJECTION_MARK;
67
import static datadog.trace.api.iast.VulnerabilityMarks.LDAP_INJECTION_MARK;
78
import static datadog.trace.api.iast.VulnerabilityMarks.NOT_MARKED;
@@ -164,6 +165,12 @@ public interface VulnerabilityType {
164165
.excludedSources(Builder.DB_EXCLUDED)
165166
.build();
166167

168+
VulnerabilityType EMAIL_HTML_INJECTION =
169+
type(VulnerabilityTypes.EMAIL_HTML_INJECTION)
170+
.mark(EMAIL_HTML_INJECTION_MARK)
171+
.excludedSources(Builder.DB_EXCLUDED)
172+
.build();
173+
167174
/* All vulnerability types that have a mark. Should be updated if new vulnerabilityType with mark is added */
168175
VulnerabilityType[] MARKED_VULNERABILITIES = {
169176
SQL_INJECTION,
@@ -177,7 +184,8 @@ public interface VulnerabilityType {
177184
XSS,
178185
HEADER_INJECTION,
179186
REFLECTION_INJECTION,
180-
UNTRUSTED_DESERIALIZATION
187+
UNTRUSTED_DESERIALIZATION,
188+
EMAIL_HTML_INJECTION
181189
};
182190

183191
String name();
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.datadog.iast.sink;
2+
3+
import com.datadog.iast.Dependencies;
4+
import com.datadog.iast.model.VulnerabilityType;
5+
import datadog.trace.api.iast.sink.EmailInjectionModule;
6+
import javax.annotation.Nullable;
7+
8+
public class EmailInjectionModuleImpl extends SinkModuleBase implements EmailInjectionModule {
9+
public EmailInjectionModuleImpl(final Dependencies dependencies) {
10+
super(dependencies);
11+
}
12+
13+
@Override
14+
public void onSendEmail(@Nullable final Object messageContent) {
15+
if (messageContent == null) {
16+
return;
17+
}
18+
checkInjection(VulnerabilityType.EMAIL_HTML_INJECTION, messageContent);
19+
}
20+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.datadog.iast.sink
2+
3+
import com.datadog.iast.IastModuleImplTestBase
4+
import com.datadog.iast.Reporter
5+
import com.datadog.iast.model.Vulnerability
6+
import com.datadog.iast.model.VulnerabilityType
7+
import com.datadog.iast.propagation.PropagationModuleImpl
8+
import datadog.trace.api.iast.SourceTypes
9+
10+
class EmailInjectionModuleTest extends IastModuleImplTestBase{
11+
12+
private EmailInjectionModuleImpl module
13+
14+
def setup() {
15+
module = new EmailInjectionModuleImpl(dependencies)
16+
}
17+
18+
@Override
19+
protected Reporter buildReporter() {
20+
return Mock(Reporter)
21+
}
22+
23+
def "test onSendEmail with null messageContent"() {
24+
when:
25+
module.onSendEmail(null)
26+
27+
then:
28+
noExceptionThrown()
29+
}
30+
31+
def "test onSendEmail with non-null messageContent"() {
32+
given:
33+
def messageContent = "test message"
34+
def propagationModule = new PropagationModuleImpl()
35+
propagationModule.taintObject(messageContent, SourceTypes.NONE)
36+
37+
when:
38+
module.onSendEmail(messageContent)
39+
40+
then:
41+
1 * reporter.report(_, _) >> { args ->
42+
def vulnerability = args[1] as Vulnerability
43+
vulnerability.type == VulnerabilityType.EMAIL_HTML_INJECTION &&
44+
vulnerability.evidence == messageContent
45+
}
46+
}
47+
}

dd-java-agent/instrumentation/commons-lang-2/src/main/java/datadog/trace/instrumentation/commonslang/StringEscapeUtilsCallSite.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public static String afterEscape(
2525
final PropagationModule module = InstrumentationBridge.PROPAGATION;
2626
if (module != null) {
2727
try {
28-
module.taintStringIfTainted(result, input, false, VulnerabilityMarks.XSS_MARK);
28+
module.taintStringIfTainted(result, input, false, VulnerabilityMarks.HTML_ESCAPED_MARK);
2929
} catch (final Throwable e) {
3030
module.onUnexpectedException("afterEscape threw", e);
3131
}

dd-java-agent/instrumentation/commons-lang-2/src/test/groovy/datadog/trace/instrumentation/commonslang/StringEscapeUtilsCallSiteTest.groovy

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import groovy.transform.CompileDynamic
88

99
import static datadog.trace.api.iast.VulnerabilityMarks.SQL_INJECTION_MARK
1010
import static datadog.trace.api.iast.VulnerabilityMarks.XSS_MARK
11+
import static datadog.trace.api.iast.VulnerabilityMarks.EMAIL_HTML_INJECTION_MARK
1112

1213
@CompileDynamic
1314
class StringEscapeUtilsCallSiteTest extends AgentTestRunner {
@@ -27,15 +28,32 @@ class StringEscapeUtilsCallSiteTest extends AgentTestRunner {
2728

2829
then:
2930
result == expected
30-
1 * module.taintStringIfTainted(_ as String, args[0], false, mark)
31+
1 * module.taintStringIfTainted(_ as String, args[0], false, XSS_MARK | EMAIL_HTML_INJECTION_MARK)
3132
0 * _
3233

3334
where:
34-
method | args | mark | expected
35-
'escapeHtml' | ['Ø-This is a quote'] | XSS_MARK | '&Oslash;-This is a quote'
36-
'escapeJava' | ['Ø-This is a quote'] | XSS_MARK | '\\u00D8-This is a quote'
37-
'escapeJavaScript' | ['Ø-This is a quote'] | XSS_MARK | '\\u00D8-This is a quote'
38-
'escapeXml' | ['Ø-This is a quote'] | XSS_MARK | '&#216;-This is a quote'
39-
'escapeSql' | ['Ø-This is a quote'] | SQL_INJECTION_MARK | 'Ø-This is a quote'
35+
method | args | expected
36+
'escapeHtml' | ['Ø-This is a quote'] | '&Oslash;-This is a quote'
37+
'escapeJava' | ['Ø-This is a quote'] | '\\u00D8-This is a quote'
38+
'escapeJavaScript' | ['Ø-This is a quote'] | '\\u00D8-This is a quote'
39+
'escapeXml' | ['Ø-This is a quote'] | '&#216;-This is a quote'
40+
}
41+
42+
void 'test #method sql'() {
43+
given:
44+
final module = Mock(PropagationModule)
45+
InstrumentationBridge.registerIastModule(module)
46+
47+
when:
48+
final result = TestStringEscapeUtilsSuite.&"$method".call(args)
49+
50+
then:
51+
result == expected
52+
1 * module.taintStringIfTainted(_ as String, args[0], false, SQL_INJECTION_MARK)
53+
0 * _
54+
55+
where:
56+
method | args | expected
57+
'escapeSql' | ['Ø-This is a quote'] | 'Ø-This is a quote'
4058
}
4159
}

dd-java-agent/instrumentation/commons-lang-3/src/main/java/datadog/trace/instrumentation/commonslang3/StringEscapeUtilsCallSite.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public static String afterEscape(
2727
final PropagationModule module = InstrumentationBridge.PROPAGATION;
2828
if (module != null) {
2929
try {
30-
module.taintStringIfTainted(result, input, false, VulnerabilityMarks.XSS_MARK);
30+
module.taintStringIfTainted(result, input, false, VulnerabilityMarks.HTML_ESCAPED_MARK);
3131
} catch (final Throwable e) {
3232
module.onUnexpectedException("afterEscape threw", e);
3333
}

dd-java-agent/instrumentation/commons-lang-3/src/test/groovy/datadog/trace/instrumentation/commonslang3/StringEscapeUtilsCallSiteTest.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class StringEscapeUtilsCallSiteTest extends AgentTestRunner {
2525

2626
then:
2727
result == expected
28-
1 * module.taintStringIfTainted(_ as String, args[0], false, VulnerabilityMarks.XSS_MARK)
28+
1 * module.taintStringIfTainted(_ as String, args[0], false, VulnerabilityMarks.HTML_ESCAPED_MARK)
2929
0 * _
3030

3131
where:

dd-java-agent/instrumentation/commons-text/src/main/java/datadog/trace/instrumentation/commonstext/StringEscapeUtilsCallSite.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public static String afterEscape(
2929
final PropagationModule module = InstrumentationBridge.PROPAGATION;
3030
if (module != null) {
3131
try {
32-
module.taintStringIfTainted(result, input, false, VulnerabilityMarks.XSS_MARK);
32+
module.taintStringIfTainted(result, input, false, VulnerabilityMarks.HTML_ESCAPED_MARK);
3333
} catch (final Throwable e) {
3434
module.onUnexpectedException("afterEscape threw", e);
3535
}

dd-java-agent/instrumentation/commons-text/src/test/groovy/datadog/trace/instrumentation/commonstext/StringEscapeUtilsCallSiteTest.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class StringEscapeUtilsCallSiteTest extends AgentTestRunner {
2525

2626
then:
2727
result == expected
28-
1 * module.taintStringIfTainted(_ as String, args[0], false, VulnerabilityMarks.XSS_MARK)
28+
1 * module.taintStringIfTainted(_ as String, args[0], false, VulnerabilityMarks.HTML_ESCAPED_MARK)
2929
0 * _
3030

3131
where:

0 commit comments

Comments
 (0)