Skip to content

Commit c45c6c3

Browse files
committed
fix(@angular/ssr): ensure public directory containment in CommonEngine
Ensure that paths resolved in `retrieveSSGPage` strictly remain within the configured `publicPath` by checking `relative()` containment before evaluating the static file. Previously, a string `startsWith()` check was used, which could match sibling directories that share the same name prefix as `publicPath`.
1 parent d3aaa48 commit c45c6c3

1 file changed

Lines changed: 6 additions & 6 deletions

File tree

packages/angular/ssr/node/src/common-engine/common-engine.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { ApplicationRef, StaticProvider, Type } from '@angular/core';
1010
import { BootstrapContext } from '@angular/platform-browser';
1111
import { renderApplication, renderModule, ɵSERVER_CONTEXT } from '@angular/platform-server';
1212
import * as fs from 'node:fs';
13-
import { dirname, join, normalize, resolve } from 'node:path';
13+
import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
1414
import { URL } from 'node:url';
1515
import { validateUrl } from '../../../src/utils/validation';
1616
import { getAllowedHostsFromEnv } from '../environment-options';
@@ -162,16 +162,16 @@ export class CommonEngine {
162162
// See: https://portswigger.net/web-security/file-path-traversal
163163
const pagePath = join(publicPath, pathname, 'index.html');
164164

165+
const relativePath = relative(publicPath, pagePath);
166+
if (relativePath.startsWith('..') || isAbsolute(relativePath)) {
167+
return undefined;
168+
}
169+
165170
if (this.pageIsSSG.get(pagePath)) {
166171
// Serve pre-rendered page.
167172
return fs.promises.readFile(pagePath, 'utf-8');
168173
}
169174

170-
if (!pagePath.startsWith(normalize(publicPath))) {
171-
// Potential path traversal detected.
172-
return undefined;
173-
}
174-
175175
if (pagePath === resolve(documentFilePath) || !(await exists(pagePath))) {
176176
// View matches with prerender path or file does not exist.
177177
this.pageIsSSG.set(pagePath, false);

0 commit comments

Comments
 (0)