Skip to content
Injection Reviewed 2026-09-12

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.

Template injection, file path injection and broken object authorization protect related but distinct boundaries.

References