Skip to content
Variable Resolution
step 1/5

Reading — step 1 of 5

Read

~1 min readVariables & Filters

Variable Resolution

Inside {{ ... }}: a path. Resolve against context (a dict).

Simple:

context = {'name': 'Alice'}
{{ name }} -> "Alice"

Nested:

context = {'user': {'name': 'Alice', 'age': 30}}
{{ user.name }} -> "Alice"

Lists:

context = {'items': [10, 20, 30]}
{{ items[0] }} -> "10"
{{ items.0 }} -> "10"   (some engines)

Method calls (Jinja2):

{{ items.append(40) }}   # mutates list
{{ name.upper() }}       # "ALICE"

Resolution algorithm:

python

Strict mode: raise on missing variables. Default mode: silently substitute empty string.

Globals: some engines have a builtin namespace (lookup vars first in context, fallback to globals).

Local scope: {% for x in items %}{{ x }}{% endfor %} introduces local var x.

Be careful with security: if context contains user-controlled data and template engine evaluates Python (__class__, __subclasses__, etc.), you have RCE. Server-Side Template Injection (SSTI).

Mitigations:

  • Sandbox: restrict attribute access (no __attrs__).
  • Whitelist methods (no os.system).
  • Don't pass user input as TEMPLATE; only as DATA.

Real CVEs from SSTI in Flask/Jinja2 = remote code execution on web servers.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…