JS: Add sinks for server-template tags in AngularJS templates

This commit is contained in:
Asger Feldthaus
2021-07-20 19:56:53 +02:00
parent d6dbabf9e0
commit 0f27bffb05
3 changed files with 62 additions and 0 deletions

View File

@@ -841,3 +841,37 @@ class NgDataFlowNode extends TNode {
)
}
}
/** Holds if everything in the given file should be considered part of an AngularJS app. */
private predicate fileIsImplicitlyAngularJS(HTML::HtmlFile file) {
// The file contains ng-* attributes.
exists(HTML::Attribute attrib |
attrib.getName().regexpMatch("ng-.*") and
attrib.getFile() = file
) and
// But does not contain the ng-app root element, implying that file is
// included from elsewhere.
not exists(HTML::Attribute attrib |
attrib.getName() = "ng-app" and
attrib.getFile() = file
)
}
/** Holds if `element` is under a `ng-non-bindable` directive, disabling interpretation by AngularJS. */
private predicate isNonBindable(HTML::Element element) {
exists(element.getParent*().getAttributeByName("ng-non-bindable"))
}
/**
* Holds if the contents and attribute values of the given element are interpreted by AngularJS,
* that is, any placeholder expressions therein, such as `{{x}}`, are evaluated and inserted in the output.
*/
predicate isInterpretedByAngularJS(HTML::Element element) {
(
fileIsImplicitlyAngularJS(element.getFile())
or
exists(element.getParent*().getAttributeByName("ng-app"))
) and
not isNonBindable(element) and
not element.getName() = "script" // script tags are never interpreted
}

View File

@@ -99,6 +99,16 @@ module Templating {
/** Holds if this placeholder occurs in JS code. */
predicate isInCodeContext() {
isInScriptTag() or isInCodeAttribute()
/**
* Holds if this placeholder occurs in the definition of another template, which means the output
* is susceptible to code injection.
*/
predicate isInNestedTemplateContext(string templateType) {
templateType = "AngularJS" and
AngularJS::isInterpretedByAngularJS(getParent()) and
// Exclude delimiters that coincide with those of AngularJS's own template engine.
// It's too unlikely to happen, more likely is that one of our heuristics got it wrong.
not getRawText().regexpMatch("(?s)\\{\\{.*\\}\\}")
}
/**

View File

@@ -65,6 +65,24 @@ module CodeInjection {
}
}
/**
* A server-side template tag occurring in the context of another template language.
*/
class TemplateTagInNestedTemplateContext extends Sink {
string templateType;
TemplateTagInNestedTemplateContext() {
exists(Templating::TemplatePlaceholderTag tag |
tag.isInNestedTemplateContext(templateType) and
this = tag.asDataFlowNode()
)
}
override string getMessageSuffix() {
result = "here and is interpreted by " + templateType + ", which may evaluate it as code"
}
}
/**
* Gets a reference to a `<script />` tag created using `document.createElement`.
*/