Skip to content

ADR-0030: Stitcher Security Invariants

Accepted

Date: 2026-06-25

Context

The Stitcher is the bounded LLM layer that fills Seams, generates UI code, and handles migration steps requiring LLM involvement. It is the only component in the platform that calls an LLM to produce artifacts that are delivered to the customer.

The security properties of an LLM-based component cannot be achieved by prompt instruction alone. Telling a model to follow constraints is probabilistic. Mechanically enforcing constraints is deterministic. This distinction is foundational to the platform’s trust story: the Stitcher’s trustworthiness comes from the harness that surrounds it, not from the model’s compliance.

Current-state research confirms the risk environment:

  • Prompt injection is ranked #1 in the OWASP Top 10 for LLM Applications (LLM01:2025), with attack success rates of 50–84% in agentic systems
  • Production exploits in AI coding tools (GitHub Copilot CVE-2025-53773, Cursor IDE CVE-2025-54795, Claude Code deny rule bypasses) demonstrate that agents with shell and network access are active targets
  • 87% of AI-generated code pull requests in independent research contained at least one security vulnerability
  • No complete fix for prompt injection exists — defence in depth is the only viable strategy

This ADR establishes the invariants that constitute Almathal’s defence-in-depth around the Stitcher. They are not aspirational guidelines; they are platform-enforced constraints.

Decision

Invariant 1: Text-Only Output — No Shell, Tool-Use, or Network Access

The Stitcher generates code as text files. It has no shell access, no tool-use capability, no ability to execute commands, and no outbound network calls during generation. It cannot read the filesystem beyond the structured handoff the Composer provides.

This is enforced at the platform infrastructure level. The model configuration and execution sandbox are set to prohibit these capabilities. A prompt injection that instructs the Stitcher to execute a shell command will fail because the capability does not exist in the execution environment, not because the model refused.

This invariant directly addresses the class of vulnerabilities that caused the Claude Code deny rule bypass (subcommand overflow), the Check Point repository config attack (shell command execution via repository-controlled configuration), and the Cymulate CVEs (path restriction bypass, command injection). Those vulnerabilities required agents with shell and network access. The Stitcher is not such an agent.

Invariant 2: Output Path Constraints

The Stitcher may only produce files at paths declared in the Seam contract’s output_files. The platform enforces this by:

  • Normalising all declared output paths and all Stitcher-produced paths to absolute paths within the generation sandbox before comparison
  • Stripping null bytes from paths before normalisation
  • Rejecting any produced file whose normalised path does not appear in the normalised declared paths list

Violation response: If the Stitcher produces output at an undeclared path, the platform hard-fails the generation immediately, discards the entire generation attempt, logs a security event (model ID, Seam ID, attempted path, invocation ID, user ID, timestamp), and surfaces a precise error to the customer.

This is a hard fail, not a silent discard. A path constraint violation is a security event and must be treated as such.

See edge case ESC-STI-003 in docs/design/edge-cases.md for path traversal and null byte attack patterns and their mitigations.

Invariant 3: Bounded Retry

The Stitcher may retry a failed Seam at most N times (default 3, platform-configurable per Archetype). After N failures, the generation hard-fails. The Stitcher cannot self-extend its retry budget. The retry bound is enforced by the platform’s retry control loop, not by the model.

Each retry receives the prior failure’s Build Verification output as additional context. This follows the harness engineering principle: failures are deterministic signals fed back into the next attempt, not open-ended prompts for the model to decide what to do.

Invariant 4: No Persistent Memory Across Invocations

Each Stitcher invocation for a Seam starts with a clean context. The Stitcher has no access to prior generations, prior customer sessions, prior Seam outputs from other builds, or any state beyond what the Composer provides in the structured handoff for this Seam.

This eliminates cross-generation context pollution and limits the blast radius of any single compromised invocation.

Invariant 5: Seam Isolation

Each Seam is processed in a separate Stitcher invocation with an isolated context. The Stitcher does not accumulate a growing context window as it processes sequential Seams within a generation.

Inter-Seam communication occurs only through declared, typed, structured handoff artifacts. For example: the backend Seam produces an OpenAPI spec fragment as a side output; the frontend Seam receives that spec as a declared input. The spec travels as a structured artifact, not as raw context.

This prevents a contaminated early Seam from polluting the context for subsequent Seams. See edge case ESC-STI-005 in docs/design/edge-cases.md.

Invariant 6: Structured Data Envelope and Resolver Guardrails

All user-supplied variation point values pass through the Resolver as an input guardrail before reaching the Stitcher. The Resolver:

Pattern detection (primary defence): Scans all free-text variation point values for injection-characteristic patterns — directive language, instruction-like phrasing, override signals, and combinations thereof. This includes common prompt injection phrasing and encoding variants. Detected patterns → immediate rejection, error returned to user, security event logged. The pattern list is maintained as a versioned internal configuration artifact and updated as new patterns emerge.

Type constraint enforcement: Enum variation point values must be in the declared options list. String values must match declared regex patterns. List items must conform to declared schemas. Values failing validation are rejected before being stored in the Spec.

Structured data envelope: User-supplied values enter the Stitcher’s context inside a clearly demarcated <user_data> block, explicitly identified as structured configuration data. The Stitcher’s governing instructions (the Seam contract) constitute the dominant context. User data is always subordinate.

The Resolver is a synchronous gate in the generation pipeline — no separate network service, no async handoff. User input passes through the Resolver before being stored in the Spec. The Stitcher receives only Resolver-validated, enveloped values.

Archetype authoring implication: Every variation point declared as type string without a pattern constraint is a deliberate choice to accept free text. Unconstrained string fields must be explicitly justified in the Archetype definition. This is a governance requirement, not an advisory.

See edge cases ESC-STI-001 and ESC-STI-002 in docs/design/edge-cases.md for full attack scenarios, blast radii, and known gaps.

Invariant 7: Manifest Content Trust Level and Envelope (V1)

For MVP, Adapter Manifest content (integration hints, usage patterns, common pitfalls) is treated as fully trusted. Manifests are platform-authored and admission-controlled; the curation pipeline’s human review process is the security control.

For V1, Manifest-sourced content will be enveloped in the Stitcher’s context, explicitly labelled as reference material rather than instructions. This is the same structured envelope principle as user data but applied to platform-internal content.

This decision reflects the principle that defence-in-depth applies even to trusted internal content. The MVP concession is made on speed grounds; the V1 hardening is committed.

See edge case ESC-STI-004 in docs/design/edge-cases.md.

Invariant 8: Generation Isolation — No Cross-Customer Context Access

Each generation runs in an isolated context. Customer A’s generation context — Spec, variation point values, entity definitions, generated files, audit trail — is inaccessible to Customer B’s generation, including:

  • In concurrent generation scenarios (multiple customers generating simultaneously)
  • Between sequential generations (one customer’s prior generation cannot be read by another)
  • At the audit trail level (audit trail access is scoped to the customer’s organization)

This is a contractual commitment, included in enterprise service agreements. Enterprise procurement will ask directly: “Can another customer’s code or context be accessed during my generation?” The answer is no, by architecture, and Almathal commits to this in writing.

This commitment is enforced through:

  • Process-level isolation between concurrent generation sandboxes
  • No shared in-memory state between generation instances
  • Audit trail access controls scoped to organizational boundaries (per ADR-0028 observability architecture)

Invariant 9: Build Verification Gates All Stitcher Output

The Stitcher’s output for every Seam is subject to Build Verification (compile, lint, smoke tests) before delivery. The Stitcher cannot bypass this gate. Failed verification triggers a retry (up to the Invariant 3 bound) with the failure as additional context.

Build Verification is deterministic. It does not trust the Stitcher’s output — it tests it. This is the most direct expression of the harness principle: the model’s good behaviour is irrelevant; what matters is that the output satisfies deterministic acceptance criteria.

Invariant 10: AI Reviewer Uses a Different Model Than the Stitcher

The AI Reviewer (post-generation advisory review) uses a different model than the Stitcher, from a different model family or provider where practical. The purpose is to prevent rubber-stamping: a model reviewing its own output is more likely to validate it uncritically.

This invariant cannot be enforced mechanically in the same way as output path constraints, but it is a platform configuration requirement. The AI Reviewer model configuration must be verified as different from the Stitcher model configuration on every platform update.

Attack Types This ADR Addresses

The following attack categories from the OWASP Top 10 for LLM Applications 2025 are addressed by the invariants above:

OWASP CategoryInvariant(s) That Address It
LLM01: Prompt InjectionInvariant 6 (Resolver guardrails), Invariant 5 (Seam isolation), Invariant 2 (output path constraints)
LLM02: Sensitive Information DisclosureInvariant 2 (output path constraints contain exfiltration scope), Invariant 4 (no persistent memory)
LLM05: Improper Output HandlingInvariant 9 (Build Verification gates all output)
LLM06: Excessive AgencyInvariant 1 (text-only, no shell/tool/network), Invariant 3 (bounded retry)
LLM07: System Prompt LeakageInvariant 6 (structured envelope limits instruction/data confusion), Invariant 2 (path constraints limit exfiltration scope)

Attack types not fully addressed by this ADR (documented in docs/design/edge-cases.md):

  • LLM03: Supply Chain — model weight compromise is addressed through provider diversification (future) and output monitoring, not by platform invariants
  • LLM04: Data and Model Poisoning — addressed through the Curation Pipeline’s admission controls (ADR-0018), not by Stitcher-level invariants
  • LLM08: Vector and Embedding Weaknesses — addressed at the generated application level (ADR-0029 AI Governance Package), not by Stitcher-level invariants
  • LLM09: Misinformation — addressed by Build Verification (functional correctness) and AI Reviewer (advisory); no complete mitigation

Rationale

Mechanical enforcement over prompt instruction is the overriding principle. No invariant in this ADR relies on the model complying with a prompt-level instruction. Every invariant is either enforced by the platform’s execution environment, enforced by validation code that runs independently of the model, or enforced by a deterministic test harness.

Defence in depth is the strategy because no single control is complete. Prompt injection has no complete fix. Accepting this and layering controls — pattern detection at input, structured envelope at prompt construction, output path enforcement at file write, Build Verification at output — means multiple independent controls must fail simultaneously for an attack to succeed.

Seam isolation balances security (smaller blast radius per invocation) against coherence (inter-Seam information flow). Structured handoff artifacts provide the coherence without the cumulative context risk.

Contractual generation isolation makes Almathal’s multi-tenant architecture a competitive advantage rather than just an operational requirement. Enterprise procurement teams operating under GDPR, CCPA, and sector-specific data protection requirements need this commitment in writing.

Invariant violations are security events, not operational errors. Hard-fail with logging distinguishes platform-level integrity violations from normal generation failures and ensures they are visible to the security team.

Future Considerations

Model evaluation protocol. Before any Stitcher model update is deployed broadly, the updated model should be evaluated against the full Archetype smoke test suite to verify invariant compliance. No formal evaluation protocol exists yet; it is a V1 operational concern.

Output content scanning — MVP scope, not deferred. Build Verification checks functional correctness (compilation, tests). It does not scan generated content for encoded system prompt data (ESC-STI-002) or shell injection patterns in string literals. An output content scanner that addresses ESC-STI-002 runs as a post-generation step before the AI Reviewer. It scans generated files for patterns matching the Stitcher’s system prompt structure in plaintext and encoded variants (base64, hex, character-by-character). Detection triggers a hard fail and security event log. This is MVP scope. The MVP is the foundation — security controls addressing known critical gaps are not deferred.

Symlink resolution in generation sandbox. The output path constraint implementation must verify that symlinks in the generation sandbox cannot redirect an in-scope path to an out-of-scope location. This is an implementation detail not currently specified.

Pattern list maintenance. The injection pattern list used by the Resolver (Invariant 6) must be treated as a security artifact — versioned, reviewed, and updated as new injection techniques emerge. The process for updating the pattern list is a V1 governance concern.

References

  • Internals → Stitcher — full component documentation for the Stitcher
  • docs/design/edge-cases.md — internal edge case catalog; ESC-STI-001 through ESC-STI-008 cover Stitcher-specific attack scenarios in detail
  • ADR-0009: Fully-Specified Seam Contracts — the Seam contract model that the Stitcher operates within
  • ADR-0012: Sanity Checks at Five Pipeline Stages — Build Verification as a deterministic gate
  • ADR-0028: Almathal AI Governance Posture — the broader governance context for AI agent operation
  • ADR-0029: Customer AI Governance Outputs — what the generated application’s audit trail contains
  • OWASP Top 10 for LLM Applications 2025 — the reference taxonomy for LLM attack categories