Skip to content

Commit 867fba8

Browse files
authored
Merge pull request #126 from advanced-security/knewbury01/e2-pii-cap
Add sensitive information exposure query
2 parents 1e27135 + 4812033 commit 867fba8

File tree

10 files changed

+172
-4
lines changed

10 files changed

+172
-4
lines changed

.github/workflows/javascript.sarif.expected

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDL.qll

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ abstract class CdlElement extends JsonObject {
3333
CdlAnnotation getAnAnnotation() { result = this.getAnnotation(_) }
3434
}
3535

36+
class CdlEntityField extends CdlElement {
37+
string name;
38+
CdlKind kind;
39+
40+
CdlEntityField() { exists(CdlDefinition definition | this = definition.getElement(name)) }
41+
42+
override string getName() { result = name }
43+
44+
override CdlKind getKind() { result = kind }
45+
}
46+
3647
class CdlService extends CdlElement {
3748
string name;
3849
CdlKind kind;
@@ -127,11 +138,46 @@ class CdlAttribute extends JsonObject {
127138
string getType() { result = this.getPropStringValue("type") }
128139

129140
int getLength() { result = this.getPropValue("length").(JsonPrimitiveValue).getIntValue() }
141+
142+
string getName() { result = name }
143+
}
144+
145+
/**
146+
* any `JsonValue` that has a `PersonalData` like annotation above it
147+
*/
148+
abstract class SensitiveAnnotatedElement extends JsonValue {
149+
abstract string getName();
130150
}
131151

132-
abstract class CdlAnnotation extends JsonValue {
152+
class SensitiveAnnotatedEntity extends SensitiveAnnotatedElement instanceof CdlEntity {
153+
SensitiveAnnotatedEntity() { exists(PersonalDataAnnotation a | a.getQualifiedElement() = this) }
154+
155+
override string getName() { result = this.(CdlEntity).getName() }
156+
157+
string getShortName() { result = this.getName().regexpCapture(".*\\.([^\\.]+$)", 1) }
158+
}
159+
160+
class SensitiveAnnotatedAttribute extends SensitiveAnnotatedElement instanceof CdlAttribute {
161+
SensitiveAnnotatedAttribute() {
162+
exists(PersonalDataAnnotation a | a.getQualifiedElement() = this)
163+
}
164+
165+
override string getName() { result = this.(CdlAttribute).getName() }
166+
}
167+
168+
/**
169+
* CDL annotations for PersonalData
170+
*/
171+
class PersonalDataAnnotation extends CdlAnnotation {
172+
PersonalDataAnnotation() { this.getName().matches("PersonalData%") }
173+
}
174+
175+
/**
176+
* CDL annotations specifically associated to `CdlElement`s
177+
*/
178+
class CdlAnnotation extends JsonValue {
133179
string annotationName;
134-
CdlElement element;
180+
JsonValue element;
135181

136182
CdlAnnotation() {
137183
this = element.getPropValue(annotationName) and
@@ -146,7 +192,7 @@ abstract class CdlAnnotation extends JsonValue {
146192
/**
147193
* Gets the CDL Element that this annotation is attached to.
148194
*/
149-
CdlElement getQualifiedElement() { result = element }
195+
JsonValue getQualifiedElement() { result = element }
150196
}
151197

152198
class ProtocolAnnotation extends CdlAnnotation {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# CAP Insertion of Sensitive Information into Log File
2+
3+
If sensitive information is written to a log entry using the CAP Node.js logging API, a malicious user may be able to gain access to user data.
4+
5+
Data annotated as `@PersonalData` should not be logged.
6+
7+
## Recommendation
8+
9+
CAP applications should not log sensitive information. Check CDS declarations for annotations before logging certain data types or fields.
10+
11+
## Examples
12+
13+
This CAP service directly logs the sensitive information.
14+
15+
```cds
16+
namespace advanced_security.log_exposure.sample_entities;
17+
18+
entity Sample {
19+
name : String(111);
20+
}
21+
22+
// annotations for Data Privacy
23+
annotate Sample with
24+
@PersonalData : { DataSubjectRole : 'Sample', EntitySemantics : 'DataSubject' }
25+
{
26+
name @PersonalData.IsPotentiallySensitive;
27+
}
28+
```
29+
30+
``` javascript
31+
import cds from '@sap/cds'
32+
const LOG = cds.log("logger");
33+
34+
const { Sample } = cds.entities('advanced_security.log_exposure.sample_entities')
35+
36+
class SampleVulnService extends cds.ApplicationService {
37+
init() {
38+
LOG.info("Received: ", Sample.name); // CAP log exposure alert
39+
}
40+
}
41+
```
42+
43+
## References
44+
45+
- OWASP 2021: [Security Logging and Monitoring Failures](https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/).
46+
- OWASP: [Logging Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html).
47+
- OWASP: [User Privacy Protection Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/User_Privacy_Protection_Cheat_Sheet.html).
48+
- SAP CAPire Documentation: [PersonalData Annotations](https://cap.cloud.sap/docs/guides/data-privacy/annotations).
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* @name Insertion of sensitive information into log files
3+
* @description Writing sensitive information to log files can allow that
4+
* information to be leaked to an attacker more easily.
5+
* @kind path-problem
6+
* @problem.severity warning
7+
* @security-severity 7.5
8+
* @precision medium
9+
* @id javascript/sensitive-log
10+
* @tags security
11+
* external/cwe/cwe-532
12+
*/
13+
14+
import javascript
15+
import advanced_security.javascript.frameworks.cap.CDS
16+
import advanced_security.javascript.frameworks.cap.CAPLogInjectionQuery
17+
import DataFlow::PathGraph
18+
19+
class SensitiveExposureSource extends DataFlow::Node {
20+
SensitiveExposureSource() {
21+
exists(PropRead p, SensitiveAnnotatedElement c |
22+
p.getPropertyName() = c.getName() and
23+
this = p
24+
)
25+
}
26+
}
27+
28+
class SensitiveLogExposureConfig extends TaintTracking::Configuration {
29+
SensitiveLogExposureConfig() { this = "SensitiveLogExposure" }
30+
31+
override predicate isSource(DataFlow::Node source) { source instanceof SensitiveExposureSource }
32+
33+
override predicate isSink(DataFlow::Node sink) { sink instanceof CdsLogSink }
34+
}
35+
36+
from SensitiveLogExposureConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
37+
where config.hasFlowPath(source, sink)
38+
select sink, source, sink, "Log entry depends on a potentially sensitive piece of information."
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace advanced_security.log_exposure.sample_entities;
2+
3+
entity Sample {
4+
name : String(111);
5+
dateOfBirth : Date;
6+
}
7+
8+
// annotations for Data Privacy
9+
annotate Sample with
10+
@PersonalData : { DataSubjectRole : 'Sample', EntitySemantics : 'DataSubject' }
11+
{
12+
name @PersonalData.IsPotentiallySensitive;
13+
dateOfBirth @PersonalData.IsPotentiallyPersonal;
14+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
nodes
2+
| sensitive-exposure.js:10:32:10:42 | Sample.name |
3+
| sensitive-exposure.js:10:32:10:42 | Sample.name |
4+
| sensitive-exposure.js:10:32:10:42 | Sample.name |
5+
edges
6+
| sensitive-exposure.js:10:32:10:42 | Sample.name | sensitive-exposure.js:10:32:10:42 | Sample.name |
7+
#select
8+
| sensitive-exposure.js:10:32:10:42 | Sample.name | sensitive-exposure.js:10:32:10:42 | Sample.name | sensitive-exposure.js:10:32:10:42 | Sample.name | Log entry depends on a potentially sensitive piece of information. |
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import cds from '@sap/cds'
2+
const LOG = cds.log("logger");
3+
4+
const { Sample } = cds.entities('advanced_security.log_exposure.sample_entities')
5+
6+
class SampleVulnService extends cds.ApplicationService {
7+
init() {
8+
/* A sensitive info log sink. */
9+
10+
LOG.info("Received: ", Sample.name); // CAP log exposure alert
11+
}
12+
13+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
sensitive-exposure/SensitiveExposure.ql

scripts/compile-all-cds-in-directory.sh

100644100755
File mode changed.

scripts/create-db-with-cds.sh

100644100755
File mode changed.

0 commit comments

Comments
 (0)