scaffolder-backend: use a const reference to helpers in the SecureTemplater

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2021-11-24 20:37:03 +01:00
parent dd62ca4bcd
commit 4f268b8ef1
2 changed files with 36 additions and 2 deletions
@@ -113,4 +113,33 @@ describe('SecureTemplater', () => {
['https://my-host.com/my-owner/my-repo'],
]);
});
it('should not allow helpers to be rewritten', async () => {
const templater = new SecureTemplater({
parseRepoUrl: () => ({
repo: 'my-repo',
owner: 'my-owner',
host: 'my-host.com',
}),
});
await templater.initializeIfNeeded();
const ctx = {
repoUrl: 'https://my-host.com/my-owner/my-repo',
};
expect(
templater.render(
'${{ ({}).constructor.constructor("parseRepoUrl = () => JSON.stringify(`inject`)")() }}',
ctx,
),
).toBe('');
expect(templater.render('${{ repoUrl | parseRepoUrl | dump }}', ctx)).toBe(
JSON.stringify({
repo: 'my-repo',
owner: 'my-owner',
host: 'my-host.com',
}),
);
});
});
@@ -45,11 +45,13 @@ const { render, renderCompat } = (() => {
compatEnv.addFilter('jsonify', compatEnv.getFilter('dump'));
if (typeof parseRepoUrl !== 'undefined') {
const safeHelperRef = parseRepoUrl;
env.addFilter('parseRepoUrl', repoUrl => {
return JSON.parse(parseRepoUrl(repoUrl))
return JSON.parse(safeHelperRef(repoUrl))
});
env.addFilter('projectSlug', repoUrl => {
const { owner, repo } = JSON.parse(parseRepoUrl(repoUrl));
const { owner, repo } = JSON.parse(safeHelperRef(repoUrl));
return owner + '/' + repo;
});
}
@@ -132,6 +134,9 @@ export class SecureTemplater {
};
}
// Note that helpers in the sandbox can be rewritten with a script injection.
// In order to mitigate that each helper must be assigned to a constant variable
// inside the closure that houses the nunjucks implementation.
this.#vm = new VM({ timeout: 1000, sandbox });
const nunjucksSource = await fs.readFile(