Dynamic template and render paths¶
What does this mean ?¶
A render operation selects and evaluates a template on the server. Allowing request data to choose that template can expose unintended views or access files outside the intended set. Code execution depends on the framework, template engine, file access and attacker control; a dynamic path alone does not prove remote code execution.
What can happen ?¶
An attacker may select an internal view or bypass the intended page flow. The consequence becomes more serious if an attacker can also write templates or select an engine that interprets a file as executable code. Authorization is still required for each resource rendered.
Recommendation¶
Map a small public identifier to a fixed, server-controlled template name. Reject unknown identifiers. Keep template sources and engine settings out of untrusted data, and pass only explicit data fields to templates. Do not replace a missing validation function with string cleanup or a path prefix check.
Sample Code¶
Unsafe: request data controls the template selection.
def show
render template: params[:page]
end
Safer: this public help controller permits only two static views. These pages contain no user-specific or protected data.
HELP_VIEWS = {
"getting-started" => "help/getting_started",
"faq" => "help/faq"
}.freeze
def show
view = HELP_VIEWS[params[:page].to_s]
return head :not_found unless view
render template: view
end
Unsafe: an end user selects the view supplied to render.
app.get('/help', (req, res) => res.render(req.query.page));
Safer: static help templates are selected through a map. The map avoids inherited object-property lookups.
const helpViews = new Map([
['getting-started', 'help/getting-started'],
['faq', 'help/faq']
]);
app.get('/help', (req, res) => {
const page = req.query.page;
const view = typeof page === 'string' ? helpViews.get(page) : undefined;
if (!view) return res.sendStatus(404);
return res.render(view, { title: 'Help' });
});
Benign regression check¶
Request each permitted help page and verify the selected fixed view. Try an unknown value, a path-like value and constructor; each must return 404 without invoking the renderer. Confirm repeated query parameters are rejected by the Express handler when its query parser returns an array.
Related guidance¶
Template injection, file path injection and broken object authorization protect related but distinct boundaries.