mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(core): reject dynamic script host elements
The previous fix for GHSA-692r-grfm-v8x7 was incomplete because it rejected script tags only when locating an explicit host element. Dynamic component instantiation can also infer the host element from the component selector.
Move the script-host rejection to the point where ComponentFactory has resolved the host element for either path, so createComponent rejects script hosts consistently.
(cherry picked from commit 135f3755b4)
This commit is contained in:
committed by
Alex Rickabaugh
parent
26831d0cbd
commit
8eb7aea08b
@@ -193,6 +193,15 @@ function createHostElement(componentDef: ComponentDef<unknown>, renderer: Render
|
||||
return createElementNode(renderer, tagName, namespace);
|
||||
}
|
||||
|
||||
function assertNotScriptHostElement(tagName: string | null | undefined): void {
|
||||
if (tagName?.toLowerCase() === 'script') {
|
||||
throw new RuntimeError(
|
||||
RuntimeErrorCode.UNSAFE_VALUE_IN_SCRIPT,
|
||||
ngDevMode && `"<script>" tag is not allowed as a component host element.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Infers the tag name that should be used for a component based on its definition.
|
||||
* @param componentDef Definition for which to resolve the tag name.
|
||||
@@ -283,6 +292,7 @@ export class ComponentFactory<T> extends AbstractComponentFactory<T> {
|
||||
rootViewInjector,
|
||||
)
|
||||
: createHostElement(cmpDef, hostRenderer);
|
||||
assertNotScriptHostElement(hostElement?.tagName);
|
||||
const hasInputBindings =
|
||||
componentBindings?.some(isInputBinding) ||
|
||||
directives?.some((d) => typeof d !== 'function' && d.bindings.some(isInputBinding));
|
||||
|
||||
@@ -21,7 +21,6 @@ import {stringify} from '../../util/stringify';
|
||||
import {assertFirstCreatePass, assertHasParent, assertLView} from '../assert';
|
||||
import {attachPatchData} from '../context_discovery';
|
||||
import {getNodeInjectable, getOrCreateNodeInjectorForNode} from '../di';
|
||||
import {RuntimeError, RuntimeErrorCode} from '../../errors';
|
||||
import {throwMultipleComponentError} from '../errors';
|
||||
import {ComponentDef, ComponentTemplate, DirectiveDef, RenderFlags} from '../interfaces/definition';
|
||||
import {
|
||||
@@ -178,12 +177,6 @@ export function locateHostElement(
|
||||
// projection.
|
||||
const preserveContent = preserveHostContent || encapsulation === ViewEncapsulation.ShadowDom;
|
||||
const rootElement = renderer.selectRootElement(elementOrSelector, preserveContent);
|
||||
if (rootElement.tagName.toLowerCase() === 'script') {
|
||||
throw new RuntimeError(
|
||||
RuntimeErrorCode.UNSAFE_VALUE_IN_SCRIPT,
|
||||
ngDevMode && `"<script>" tag is not allowed as a component host element.`,
|
||||
);
|
||||
}
|
||||
applyRootElementTransform(rootElement as HTMLElement);
|
||||
return rootElement;
|
||||
}
|
||||
|
||||
@@ -807,6 +807,19 @@ describe('innerHTML processing', () => {
|
||||
});
|
||||
});
|
||||
describe('Component host element validation', () => {
|
||||
it('should throw an error when dynamically creating a component with a script selector', () => {
|
||||
@Component({
|
||||
selector: 'script',
|
||||
template: '',
|
||||
})
|
||||
class ScriptHost {}
|
||||
|
||||
const environmentInjector = TestBed.inject(EnvironmentInjector);
|
||||
expect(() => {
|
||||
createComponent(ScriptHost, {environmentInjector});
|
||||
}).toThrowError(/"<script>" tag is not allowed as a component host element/);
|
||||
});
|
||||
|
||||
it('should throw an error when dynamically mounting a component onto a script tag', () => {
|
||||
@Component({
|
||||
selector: 'my-sink',
|
||||
|
||||
@@ -344,6 +344,7 @@
|
||||
"areAnimationSupported",
|
||||
"arrRemove",
|
||||
"assertNotDestroyed",
|
||||
"assertNotScriptHostElement",
|
||||
"attachPatchData",
|
||||
"balancePreviousStylesIntoKeyframes",
|
||||
"balanceProperties",
|
||||
|
||||
@@ -315,6 +315,7 @@
|
||||
"areAnimationSupported",
|
||||
"arrRemove",
|
||||
"assertNotDestroyed",
|
||||
"assertNotScriptHostElement",
|
||||
"attachPatchData",
|
||||
"bind",
|
||||
"bindingUpdated",
|
||||
|
||||
@@ -375,6 +375,7 @@
|
||||
"assertAllValuesPresent",
|
||||
"assertControlPresent",
|
||||
"assertNotDestroyed",
|
||||
"assertNotScriptHostElement",
|
||||
"assertPlatform",
|
||||
"attachPatchData",
|
||||
"baseElement",
|
||||
|
||||
@@ -380,6 +380,7 @@
|
||||
"assertAllValuesPresent",
|
||||
"assertControlPresent",
|
||||
"assertNotDestroyed",
|
||||
"assertNotScriptHostElement",
|
||||
"assertPlatform",
|
||||
"attachPatchData",
|
||||
"baseElement",
|
||||
|
||||
@@ -311,6 +311,7 @@
|
||||
"areAnimationSupported",
|
||||
"arrRemove",
|
||||
"assertNotDestroyed",
|
||||
"assertNotScriptHostElement",
|
||||
"attachPatchData",
|
||||
"baseElement",
|
||||
"bind",
|
||||
|
||||
@@ -421,6 +421,7 @@
|
||||
"arrRemove",
|
||||
"arrayEquals",
|
||||
"assertNotDestroyed",
|
||||
"assertNotScriptHostElement",
|
||||
"attachPatchData",
|
||||
"baseElement",
|
||||
"bind",
|
||||
|
||||
@@ -250,6 +250,7 @@
|
||||
"areAnimationSupported",
|
||||
"arrRemove",
|
||||
"assertNotDestroyed",
|
||||
"assertNotScriptHostElement",
|
||||
"attachPatchData",
|
||||
"baseElement",
|
||||
"bind",
|
||||
|
||||
Reference in New Issue
Block a user