Security model · compiler v1.0.0
Evidence, boundaries, and unfinished work.
Security confidence should come from a small explicit boundary, reproducible checks, and honest records of what has not been proven—not from a green badge or a large adjective.
Know what is trusted
A template, its static markup, and its embedded Go are trusted application source. Someone allowed to edit a .sando file can write ordinary Go statements and should receive the same trust as any other application-code contributor.
Ordinary values supplied to generated components are untrusted data. For supported contexts, the security objective is that those values remain data: they must not change HTML structure, escape a quoted attribute, create executable code, or introduce a disallowed URL scheme unless trusted application code makes an explicit security-sensitive decision.
What the current implementation demonstrates
- Dynamic output is accepted only in enumerated HTML text, quoted attribute, URL, and RCDATA contexts. Script and style interpolation requires explicit trusted types.
- Dynamic tag or attribute names, unquoted attributes, event-handler values, dynamic style attributes, foreign SVG or MathML content, URL lists,
srcdoc, meta refresh, malformed HTML, and ambiguous parser states are rejected. - Ordinary URL values are normalized and checked before output. Only relative URLs and the
http,https,mailto, andtelschemes are accepted without an explicitTrustedURL. - Writer errors and contract-violating short writes propagate to the caller.
generateandcheckdo not execute project code, invoke the Go toolchain, fetch dependencies, or editgo.mod.himesan devis a separate command that intentionally builds and executes trusted project code.- Generation checks observed file ownership and filesystem boundaries, constructs affected outputs in memory before writing, and atomically replaces each changed owned file.
These are point-in-time implementation and test observations. Each statement is narrower than “secure,” and each remains subject to the exact commit, platform, and cases recorded in the evidence ledger.
Contextual output
The compiler tracks the HTML parser context around each dynamic expression. Unsupported or ambiguous contexts fail generation instead of falling back to raw output. Generated component insertion with <?~ is allowed only at an HTML content boundary, and the generated component must finish in the same parser context in which it began.
The security objective follows the same high-level trust model documented by Go's html/template: template authors are trusted while rendered data is not. The implementations and accepted languages differ. Current tests cover fixed adversarial cases; broader systematic browser-parser and html/template differential testing remains assurance work and equivalence is not claimed.
Explicit trust is a capability
The runtime has opaque TrustedHTML, TrustedURL, TrustedJS, and TrustedCSS values. The conspicuous Trust* functions create them, but do not sanitize, validate, or make unsafe bytes safe. They record an application decision to accept responsibility for those bytes.
himesan check emits best-effort lexical audit hints for direct trusted-value use visible inside .sando source. It is not Go type analysis, taint analysis, or a complete inventory of trust introduced transitively by handwritten Go.
A handwritten implementation of sando.Component is also a trusted output capability. It can write arbitrary bytes, change parser context, recurse, block, panic, or perform side effects. The compiler's balanced-context proof applies to generated components; the open Go interface does not extend that proof to handwritten implementations.
Important limits
- URL scheme checks do not decide whether a destination is authorized, same-origin, private, or otherwise trustworthy. Applications must validate destinations for sensitive sinks.
- Trusted raw HTML, JavaScript, and CSS must preserve the surrounding parser state, including container-closing and legacy parser-transition sequences.
- The runtime does not impose output-size, recursion, CPU, allocation, or time limits; recover panics; or make an arbitrary writer transactional. Applications own buffering, deadlines, bounded writers, input limits, and panic policy.
- The compiler has no hard source-size, memory, or compile-time budget and does not defend against a hostile local actor racing filesystem paths between inspection and use.
- The development supervisor is host-local, not user-authenticated. It executes project code with the user's environment and is not a production proxy, TLS terminator, deployment system, or safe runner for untrusted repositories.
The full set of assumptions and non-goals lives in the canonical threat model.
Reproducible evidence, with caveats
The current security evidence ledger names assessment dates, public identities, operating environments, commands, observed results, release findings, and open assurance gaps. It records ordinary and race-enabled tests, static analysis, dependency inventory, known-vulnerability scanning, bounded fuzz smoke, contextual-output cases, filesystem cases, and development-proxy cases.
The exact RC candidate passed native Linux/amd64 and Apple Silicon macOS/arm64 lanes with pinned Go 1.26.7 and Go 1.27.0. The compiler and runtime each declare zero third-party Go module requirements. Signed runtime and compiler tags, direct and public-proxy resolution, reproducible archives, checksums, SPDX SBOMs, and source/build provenance form the release boundary.
Coverage percentages measure statements executed, not security. A clean known-vulnerability scan cannot find unknown defects or design errors. A bounded fuzz run is a robustness observation, not a semantic proof. “Pass” means the named check produced its expected result in the named environment on that date.
The RC.1 macOS DMG is Developer ID-signed, notarized, stapled, and Gatekeeper-assessed; its unsigned native archive is reproducible before signing. Signing-key restoration and independent credential recovery remain deferred assurance work, not completed evidence. An independent install check awaits alternate Apple Silicon hardware. v1.0.0 does not imply an independent audit, external certification, or broader platform promises.
Report a vulnerability privately
Email security@sandwichhime.com. The domain delivery path has been confirmed by the owner; its private destination is intentionally not published. Do not put an undisclosed vulnerability, working exploit, credential, secret, or personal data in a public issue. Ordinary email is not end-to-end encrypted, so minimize sensitive data and never send production secrets.
Best-effort targets—not an SLA—are acknowledgement within 7 calendar days, an initial severity and scope assessment within 14 days when a reproducible issue is available, and an update at least every 30 days while an accepted report remains unresolved. Health, disability, family responsibility, missing evidence, or incident complexity may cause delay; the maintainer will communicate honestly when safely able.
Good-faith research should use local copies and systems the researcher owns or is authorized to test. This policy does not authorize active testing of the live website, Gitea, project infrastructure, or third-party deployments. Stop if testing risks availability, privacy, data integrity, or another person's account.
Read the complete security policy and the canonical security.txt before reporting. See the technical guide for the generated API and workflow.