Template trust model
Running a cxg code template is running a program. This page states exactly what that program can reach, backs it with a probe run against the shipped binary, and gives you the mitigations that actually apply. It is not a disclaimer to skim. It is the property you threat-model against before running a template you did not write.
The boundary is a process boundary
Section titled “The boundary is a process boundary”There is no security boundary between cxg and the code template it runs. cxg resolves the template’s language, launches the interpreter or compiled binary as a child process, and reads its standard output. That is the whole relationship. See how cxg executes templates for where this sits in the engine.
Everything to the right of the cxg process inherits your identity:
flowchart LR
U["your shell<br/>uid 1000"] --> C["cxg process"]
C --> E["language engine"]
E --> T["template<br/>child process"]
T --> FS[("your filesystem<br/>~/.ssh, ~/.aws")]
T --> NET(["any network host"])
T --> P["further processes"]
class T emphasis
The dashed boundary a reader might expect around the template, the box that stops it reaching your SSH keys or the internet, does not exist.
What a probe actually saw
Section titled “What a probe actually saw”This is not inference from the source. A template run under a stock scan on cxg 1.3.0 reported the following about its own process:
{ "uid": 502, "user": "animeshsrivastava", "home_listing_count": 86, "ssh_dir_readable": true, "spawned_process": "child process ran", "outbound_dns": true}It ran as the invoking user, listed that user’s home directory, read ~/.ssh,
launched a child process, and resolved an external hostname. A template can do
anything you can do: read your credentials, write to your disk, connect anywhere,
spawn anything.
The sandbox: config never changed this, and 1.3.0 removed it
Section titled “The sandbox: config never changed this, and 1.3.0 removed it”Through 1.2.0, cxg config generate wrote a sandbox: block holding enabled,
memory_limit_mb, cpu_limit_percent, network_access, and
filesystem_access. It looked like a confinement policy and enforced nothing. Re-running the probe
above with a config that set enabled: true and filesystem_access: readonly
produced the identical result: uid 502, ~/.ssh readable, child spawned, DNS
resolved.
1.3.0 deleted the block. A config it generates has no sandbox: section, and a
config that still carries one from an earlier version draws a warning rather than
being silently accepted:
warning: ./legacy-sandbox.yaml contains a `sandbox:` section.
These settings never took effect. `enabled`, `memory_limit_mb`,`cpu_limit_percent`, `network_access` and `filesystem_access` wereparsed and then ignored — no code path has ever read them to confineanything. A config setting them was not protected by them.If you inherited a config with those keys, delete them, and do not build a threat model on them in any version.
Threat-modelling with this
Section titled “Threat-modelling with this”Because the boundary is the process, isolation is your responsibility at a layer cxg does not control. Assume any template you run has your full access, and place the boundary yourself:
- Run scans somewhere disposable. A container or VM that holds no credentials worth stealing. The blast radius of a hostile template is whatever that environment can reach.
- Use an unprivileged scanning identity. A dedicated user with no SSH keys
and no cloud credentials in its environment. The probe above read
~/.sshbecause it was there to read. - Review third-party templates before running them. A template is a script you are about to execute as yourself. Read it the way you would read any such script.
- Prefer YAML for anything you have not read. A YAML template cannot execute arbitrary code. Its runtime is cxg’s own parser, and it can only issue requests and match responses. That is a genuinely smaller trust surface, by construction.
The short version
Section titled “The short version”A code template is trusted code running as you. There is no layer inside cxg that reduces that, so the layer has to be outside cxg. Decide where your isolation boundary is before you run someone else’s template, not after.
Related
Section titled “Related”- How cxg executes templates explains why the boundary is a process boundary.
- Why polyglot templates covers the cost this is one of.
- Write your first template builds a template you wrote, and therefore trust.

