# sandbox

URL: /kida/api/sandbox/
Section: api
Description: Sandboxed template execution — defense-in-depth for risky templates.

``SandboxedEnvironment`` restricts attribute access, callable types, range
sizes, and imports to reduce the blast radius of a template that attempts to
reach out of its intended context. It is **not** an isolation boundary: it
does not restrict CPU, memory, or wall-clock use; it does not sandbox objects
you place in the render context; and the Python object model is large enough
that novel escapes are possible.

**Never render fully untrusted template source against a production context
with this sandbox alone.** Combine it with OS-level isolation (process
boundary, container, seccomp, WASM, etc.), a curated render context of
primitive types, and a wall-clock timeout. See ``SECURITY.md`` for the full
threat model and hardening guidance.

Usage::

    from kida import SandboxedEnvironment

    env = SandboxedEnvironment()
    # Templates cannot access __dunder__ attributes, call unsafe functions,
    # or import modules.
    env.from_string("{{ user.name }}").render(user=user)  # OK
    env.from_string("{{ user.__class__ }}").render(user=user)  # blocked

Custom policy::

    from kida.sandbox import SandboxPolicy, SandboxedEnvironment

    policy = SandboxPolicy(
        allowed_attributes={"name", "title", "items", "keys", "values"},
        blocked_types={type, type(lambda: 0)},
    )
    env = SandboxedEnvironment(sandbox_policy=policy)

---

> For a complete page index, fetch /kida/llms.txt.

Open LLM text
(/kida/api/sandbox/index.txt)

Share with AI

Ask Claude
(https://claude.ai/new?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fsandbox%2Findex.txt)

Ask ChatGPT
(https://chatgpt.com/?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fsandbox%2Findex.txt)

Ask Gemini
(https://gemini.google.com/app?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fsandbox%2Findex.txt)

Ask Copilot
(https://copilot.microsoft.com/?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fsandbox%2Findex.txt)

Module

#
`sandbox`

Sandboxed template execution — defense-in-depth for risky templates.

`SandboxedEnvironment`restricts attribute access, callable types, range
sizes, and imports to reduce the blast radius of a template that attempts to
reach out of its intended context. It is not an isolation boundary: it
does not restrict CPU, memory, or wall-clock use; it does not sandbox objects
you place in the render context; and the Python object model is large enough
that novel escapes are possible.

Never render fully untrusted template source against a production context
with this sandbox alone. Combine it with OS-level isolation (process
boundary, container, seccomp, WASM, etc.), a curated render context of
primitive types, and a wall-clock timeout. See`SECURITY.md`for the full
threat model and hardening guidance.

Usage::

```
from kida import SandboxedEnvironment

env = SandboxedEnvironment()
# Templates cannot access __dunder__ attributes, call unsafe functions,
# or import modules.
env.from_string("{{ user.name }}").render(user=user)  # OK
env.from_string("{{ user.__class__ }}").render(user=user)  # blocked
```

Custom policy::

```
from kida.sandbox import SandboxPolicy, SandboxedEnvironment

policy = SandboxPolicy(
    allowed_attributes={"name", "title", "items", "keys", "values"},
    blocked_types={type, type(lambda: 0)},
)
env = SandboxedEnvironment(sandbox_policy=policy)
```

3Classes7Functions

## Classes

`SandboxPolicy`

8

▼

Configuration for sandbox restrictions.

Configuration for sandbox restrictions.

#### Attributes

Name
Type
Description

`allowed_attributes`

`frozenset[str] | None`

If set, only these attribute names are accessible (plus safe collection methods). If None, all non-blocked attributes are allowed.

`blocked_attributes`

`frozenset[str]`

Additional attribute names to block (merged with the built-in blocked set).

`blocked_types`

`frozenset[type]`

Object types that cannot be accessed at all. Default blocks function, type, and code objects.

`allow_import`

`bool`

Whether`__import__`is available. Default: False.

`allow_mutating_methods`

`bool`

Whether mutating collection methods (append, pop, clear, etc.) are accessible. Default: False.

`allow_calling`

`frozenset[str] | None`

Set of type names whose instances may be called. If None (default), all callables obtained via attribute access are allowed. Pass an empty frozenset to block all calls.

`max_output_size`

`int | None`

Maximum render output length in characters. None means unlimited.

`max_range`

`int`

Maximum range() size. Default: 10000.

`SecurityError`

1

▼

Raised when a sandbox policy violation is detected.

Includes an error code and actionable suggesti…

Raised when a sandbox policy violation is detected.

Includes an error code and actionable suggestion for resolving the
violation. All security errors inherit from TemplateError, so they
are caught by`except TemplateError`.

Example::

```
SecurityError: Access to attribute '__class__' is blocked by sandbox policy
  Hint: Remove the attribute access, or add '__class__' to
        SandboxPolicy(allowed_attributes=...) if you trust this template.
  Docs: https://lbliii.github.io/kida/docs/errors/#k-sec-001
```

#### Methods

Internal Methods
1

▼

`__init__`

3

▼

`def __init__(self, message: str, *, code: ErrorCode | None = None, suggestion: str | None = None)`

##### Parameters

Name
Type
Description

`message`
`—`

`code`
`—`

Default:`None`

`suggestion`
`—`

Default:`None`

`SandboxedEnvironment`

2

▼

Environment subclass that enforces sandbox restrictions.

All templates compiled by this environmen…

Environment subclass that enforces sandbox restrictions.

All templates compiled by this environment use sandboxed attribute access,
restricted builtins, and policy-enforced limits.

The sandbox intercepts:

- Attribute access (blocks dunder, unsafe types)

- `__import__`(disabled by default)

- `range()`(size-limited)

- Template output (optional size limit)

Example::

```
env = SandboxedEnvironment()
tmpl = env.from_string("{{ user.name }}")
tmpl.render(user={"name": "Alice"})  # OK

tmpl = env.from_string("{{ user.__class__.__mro__ }}")
tmpl.render(user="hello")  # raises SecurityError
```

Custom policy::

```
from kida.sandbox import SandboxPolicy
policy = SandboxPolicy(allowed_attributes=frozenset({"name", "email"}))
env = SandboxedEnvironment(sandbox_policy=policy)
```

#### Attributes

Name
Type
Description

`sandbox_policy`

`SandboxPolicy | None`

—

#### Methods

Internal Methods
1

▼

`__post_init__`

0

▼

`def __post_init__(self) -> None`

## Functions

`_is_attr_blocked`

2

`bool`

▼

Check if an attribute name is blocked by the policy.

`def _is_attr_blocked(name: str, policy: SandboxPolicy) -> bool`

##### Parameters

Name
Type
Description

`name`
`str`

`policy`
`SandboxPolicy`

##### Returns

`bool`

`_is_type_blocked`

2

`bool`

▼

Check if an object's type is blocked.

`def _is_type_blocked(obj: object, policy: SandboxPolicy) -> bool`

##### Parameters

Name
Type
Description

`obj`
`object`

`policy`
`SandboxPolicy`

##### Returns

`bool`

`_make_sandboxed_getattr`

1

▼

Create a sandboxed version of safe_getattr.

`def _make_sandboxed_getattr(policy: SandboxPolicy)`

##### Parameters

Name
Type
Description

`policy`
`SandboxPolicy`

`_make_sandboxed_getattr_none`

1

▼

Create a sandboxed version of getattr_preserve_none.

`def _make_sandboxed_getattr_none(policy: SandboxPolicy)`

##### Parameters

Name
Type
Description

`policy`
`SandboxPolicy`

`_make_sandboxed_range`

1

▼

Create a range() that enforces max_range.

`def _make_sandboxed_range(policy: SandboxPolicy)`

##### Parameters

Name
Type
Description

`policy`
`SandboxPolicy`

`_make_sandboxed_call`

1

▼

Create a call interceptor that blocks unsafe callables.

When ``policy.allow_ca…

`def _make_sandboxed_call(policy: SandboxPolicy)`

Create a call interceptor that blocks unsafe callables.

When`policy.allow_calling`is None, all callables are permitted
(attribute-level checks are still enforced). When set to a
frozenset of type names, only instances of those types may be called.
Blocked types (function, type, code) are always denied.

##### Parameters

Name
Type
Description

`policy`
`SandboxPolicy`

`patch_template_namespace`

2

`None`

▼

Patch a template namespace dict to enforce sandbox restrictions.

Called by Tem…

`def patch_template_namespace(namespace: dict[str, Any], policy: SandboxPolicy) -> None`

Patch a template namespace dict to enforce sandbox restrictions.

Called by Template.init when the environment is a SandboxedEnvironment.
Replaces unsafe functions with sandboxed versions.

##### Parameters

Name
Type
Description

`namespace`
`dict[str, Any]`

`policy`
`SandboxPolicy`
