Skip to content

Commit acf1628

Browse files
authored
Merge pull request #137 from advanced-security/knewbury01/e2-pii-cap
Add fully qualified name matching on E2 sources
2 parents a4c88fe + 1c141c4 commit acf1628

File tree

4 files changed

+68
-9
lines changed

4 files changed

+68
-9
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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,17 @@ class CdlAttribute extends JsonObject {
142142
string getName() { result = name }
143143
}
144144

145+
/**
146+
* a `CdlEntity` that is declared in a namespace
147+
*/
148+
class NamespacedEntity extends JsonObject instanceof CdlEntity {
149+
string namespace;
150+
151+
NamespacedEntity() { this.getParent+().getPropValue("namespace").getStringValue() = namespace }
152+
153+
string getNamespace() { result = namespace }
154+
}
155+
145156
/**
146157
* any `JsonValue` that has a `PersonalData` like annotation above it
147158
*/

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,32 @@ class CdsFacade extends API::Node {
1515
Node getNode() { result = this.asSource() }
1616
}
1717

18+
/**
19+
* A call to `entities` on a CDS facade.
20+
*/
21+
class CdsEntitiesCall extends API::Node {
22+
CdsEntitiesCall() { exists(CdsFacade cds | this = cds.getMember("entities")) }
23+
}
24+
25+
/**
26+
* An entity instance obtained by the entity's namespace,
27+
* via `cds.entities`
28+
* ```javascript
29+
* // Obtained through `cds.entities`
30+
* const { Service1 } = cds.entities("sample.application.namespace");
31+
* ```
32+
*/
33+
class EntityEntry extends DataFlow::CallNode {
34+
EntityEntry() { exists(CdsEntitiesCall c | c.getACall() = this) }
35+
36+
/**
37+
* Gets the namespace that this entity belongs to.
38+
*/
39+
string getNamespace() {
40+
result = this.getArgument(0).getALocalSource().asExpr().(StringLiteral).getValue()
41+
}
42+
}
43+
1844
/**
1945
* A call to `serve` on a CDS facade.
2046
*/

javascript/frameworks/cap/src/sensitive-exposure/SensitiveExposure.ql

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* @problem.severity warning
77
* @security-severity 7.5
88
* @precision medium
9-
* @id javascript/sensitive-log
9+
* @id js/sensitive-log
1010
* @tags security
1111
* external/cwe/cwe-532
1212
*/
@@ -16,19 +16,41 @@ import advanced_security.javascript.frameworks.cap.CDS
1616
import advanced_security.javascript.frameworks.cap.CAPLogInjectionQuery
1717
import DataFlow::PathGraph
1818

19-
class SensitiveExposureSource extends DataFlow::Node {
20-
SensitiveExposureSource() {
21-
exists(PropRead p, SensitiveAnnotatedElement c |
22-
p.getPropertyName() = c.getName() and
23-
this = p
24-
)
19+
SourceNode entityAccesses(TypeTracker t, string entityNamespace) {
20+
t.start() and
21+
exists(EntityEntry e | result = e and entityNamespace = e.getNamespace())
22+
or
23+
exists(TypeTracker t2 | result = entityAccesses(t2, entityNamespace).track(t2, t))
24+
}
25+
26+
SourceNode entityAccesses(string entityNamespace) {
27+
result = entityAccesses(TypeTracker::end(), entityNamespace)
28+
}
29+
30+
class SensitiveExposureFieldSource extends DataFlow::Node {
31+
SensitiveAnnotatedAttribute cdsField;
32+
SensitiveAnnotatedEntity entity;
33+
string namespace;
34+
35+
SensitiveExposureFieldSource() {
36+
this = entityAccesses(namespace).getAPropertyRead().getAPropertyRead() and
37+
//field name is same as some cds declared field
38+
this.(PropRead).getPropertyName() = cdsField.getName() and
39+
//entity name is the same as some cds declared entity
40+
entityAccesses(namespace).getAPropertyRead().toString() = entity.getShortName() and
41+
//and that field belongs to that entity in the cds
42+
entity.(CdlEntity).getAttribute(cdsField.getName()) = cdsField and
43+
//and the namespace is the same (fully qualified id match)
44+
entity.(NamespacedEntity).getNamespace() = namespace
2545
}
2646
}
2747

2848
class SensitiveLogExposureConfig extends TaintTracking::Configuration {
2949
SensitiveLogExposureConfig() { this = "SensitiveLogExposure" }
3050

31-
override predicate isSource(DataFlow::Node source) { source instanceof SensitiveExposureSource }
51+
override predicate isSource(DataFlow::Node source) {
52+
source instanceof SensitiveExposureFieldSource
53+
}
3254

3355
override predicate isSink(DataFlow::Node sink) { sink instanceof CdsLogSink }
3456
}

0 commit comments

Comments
 (0)