Skip to content
Report library
Purpose / Other

Stitch Loop Skill Security Audit

What the author says it does (original text)

Teaches agents to iteratively build websites using Stitch with an autonomous baton-passing loop pattern

Independent security check

Do not install or run it yet

Files checked
6
Risks found
6
Could it run dangerous commands?Looks for programs run straight after downloading, remote control of your computer, and hidden commands.Risks found: 1
Medium risk

An unpinned global npx installation executes remotely resolved code

Source references: 1
What we found

The README instructs users to run `npx skills add ... --global` without pinning either the `skills` CLI or the remote repository to an immutable version. `npx` normally obtains and executes the package resolved at installation time, while the global option creates persistent user-level installation state.

Why this matters

If the npm package, repository, or current release is compromised, the command could execute malicious installation logic with the user's permissions and persistently alter global Skill configuration. Even without compromise, a future version may differ from the audited source.

The README invokes an unpinned `skills` CLI through `npx`, installs from a repository identifier without an immutable version or commit, and uses `--global`. It may fetch and execute whatever code resolves at installation time and persist the skill at user scope. This does not show malicious code, but it weakens the link between this audit and what is later installed. The user can require pinned CLI and commit versions and inspect the package before installation.

README.md:5In the instructionsOpen original file
## Install```bashnpx skills add google-labs-code/stitch-skills --skill stitch-loop --global```
Could it expose your files or keys?Looks for uploads of files containing passwords or keys, and keys written directly in the code.Risks found: 1
High risk

Remotely generated active HTML is published and rendered without a security review

Source references: 3
What we found

The Skill downloads HTML returned by Stitch, moves it directly into `site/public`, and optionally starts a server and opens the page. The workflow calls only for visual comparison, not inspection of scripts, outbound requests, form destinations, embeds, or dangerous URLs.

Why this matters

If generation output, the upstream service, or its prompt is manipulated, JavaScript, trackers, or forms could send visitor input and browser-accessible data to external services during preview or deployment, or present deceptive content.

The skill downloads HTML from a Stitch-provided URL, moves it into the public directory, and may open it through a local server. The visible workflow specifies asset-path fixes and visual comparison but no inspection of scripts, external requests, forms, or embeds. Thus, if the remote output contains active content, browser verification or later deployment could execute or publish it. The user can require static review before opening or publishing and restrict network/browser permissions.

SKILL.md:90In the instructionsOpen original file
   - After generating each screen, call `[prefix]:get_project` again and update the `screens` map in `.stitch/metadata.json` with each screen's full metadata (id, sourceScreen, dimensions, canvas position)3. **Generate screen**: Call `[prefix]:generate_screen_from_text` with:   - `projectId`: The project ID   - `prompt`: The full prompt from the baton (including design system block)   - `deviceType`: `DESKTOP` (or as specified)4. **Retrieve assets**: Before downloading, check if `.stitch/designs/{page}.html` and `.stitch/designs/{page}.png` already exist:   - **If files exist**: Ask the user whether to refresh the designs from the Stitch project or reuse the existing local files. Only re-download if the user confirms.   - **If files do not exist**: Proceed with download:     - `htmlCode.downloadUrl` — Download and save as `.stitch/designs/{page}.html`      - `screenshot.downloadUrl` — Append `=w{width}` to the URL before downloading, where `{width}` is the `width` value from the screen metadata (Google CDN serves low-res thumbnails by default). Save as `.stitch/designs/{page}.png`
Show 2 other places
SKILL.md:102In the instructionsOpen original file
1. Move generated HTML from `.stitch/designs/{page}.html` to `site/public/{page}.html`2. Fix any asset paths to be relative to the public folder3. Update navigation:   - Find existing placeholder links (e.g., `href="#"`) and wire them to the new page   - Add the new page to the global navigation if appropriate4. Ensure consistent headers/footers across all pages
SKILL.md:114In the instructionsOpen original file
1. **Check availability**: Run `list_tools` to see if `chrome*` tools are present2. **Start dev server**: Use Bash to start a local server (e.g., `npx serve site/public`)3. **Navigate to page**: Call `[chrome_prefix]:navigate` to open `http://localhost:3000/{page}.html`4. **Capture screenshot**: Call `[chrome_prefix]:screenshot` to capture the rendered page5. **Visual comparison**: Compare against the Stitch screenshot (`.stitch/designs/{page}.png`) for fidelity6. **Stop server**: Terminate the dev server process
Could it delete files or keep running?Looks for broad file deletion, disk overwrites, and programs set to start automatically.Risks found: 2
High risk

A baton-controlled page name can escape intended directories or overwrite site files

Source references: 4
What we found

The protocol takes the name directly from the YAML `page` field and interpolates it into download and move paths. The main execution protocol does not require rejecting `/`, `..`, absolute paths, or an existing public destination; its confirmation step checks only whether staged HTML/PNG files already exist.

Why this matters

A malicious or mistaken baton page name could place generated content outside `.stitch/designs` or `site/public`, or replace an existing public page without explicit confirmation. The reach depends on the agent's write permissions.

The workflow directly inserts the baton's `page` value into download and public-site paths. Another document says it must be a “valid filename,” but gives no concrete rejection rules for absolute paths, `..`, separators, or an existing public target. If untrusted content can alter the baton, a crafted name could redirect writes or moves outside the intended directory. The user can require a strict basename allowlist and confirmation before replacement.

SKILL.md:63In the instructionsOpen original file
Parse `.stitch/next-prompt.md` to extract:- **Page name** from the `page` frontmatter field- **Prompt content** from the markdown body
Show 3 other places
SKILL.md:94In the instructionsOpen original file
   - `deviceType`: `DESKTOP` (or as specified)4. **Retrieve assets**: Before downloading, check if `.stitch/designs/{page}.html` and `.stitch/designs/{page}.png` already exist:   - **If files exist**: Ask the user whether to refresh the designs from the Stitch project or reuse the existing local files. Only re-download if the user confirms.   - **If files do not exist**: Proceed with download:     - `htmlCode.downloadUrl` — Download and save as `.stitch/designs/{page}.html`      - `screenshot.downloadUrl` — Append `=w{width}` to the URL before downloading, where `{width}` is the `width` value from the screen metadata (Google CDN serves low-res thumbnails by default). Save as `.stitch/designs/{page}.png`
SKILL.md:102In the instructionsOpen original file
1. Move generated HTML from `.stitch/designs/{page}.html` to `site/public/{page}.html`2. Fix any asset paths to be relative to the public folder3. Update navigation:
resources/baton-schema.md:56In the instructionsOpen original file
Before completing an iteration, validate your baton:- [ ] `page` frontmatter field exists and is a valid filename- [ ] Prompt includes the design system block- [ ] Prompt describes a page NOT already in `SITE.md` sitemap- [ ] Prompt includes specific page structure details
Medium risk

Mandatory baton continuation expands future file changes without per-iteration approval

Source references: 4
What we found

Every iteration must create another task, and the agent may invent a page when the roadmap is empty. Integration can then alter global navigation, headers and footers across all pages, and site documentation. CI/CD may continue on baton changes, while human review is only one optional orchestration method.

Why this matters

Authorization for one page can turn into multiple separately unapproved page, navigation, and documentation changes, overwriting human work or repeatedly consuming Stitch and CI resources.

Every iteration must write another task, and the agent may invent a page when the backlog is empty. Integration can also modify global navigation, headers and footers across pages, and site documentation. The document lists CI/CD triggered by baton changes, while human review is only one optional orchestration method. If automatic triggering is enabled, changes could continue and expand without per-iteration approval. The user can limit execution to one iteration, require approval each round, and allowlist writable paths.

SKILL.md:104In the instructionsOpen original file
2. Fix any asset paths to be relative to the public folder3. Update navigation:   - Find existing placeholder links (e.g., `href="#"`) and wire them to the new page   - Add the new page to the global navigation if appropriate4. Ensure consistent headers/footers across all pages
Show 3 other places
SKILL.md:124In the instructionsOpen original file
Modify `.stitch/SITE.md`:- Add the new page to Section 4 (Sitemap) with `[x]`- Remove any idea you consumed from Section 6 (Creative Freedom)- Update Section 5 (Roadmap) if you completed a backlog item### Step 6: Prepare the Next Baton (Critical)**You MUST update `.stitch/next-prompt.md` before completing.** This keeps the loop alive.1. **Decide the next page**:    - Check `.stitch/SITE.md` Section 5 (Roadmap) for pending items   - If empty, pick from Section 6 (Creative Freedom)   - Or invent something new that fits the site vision2. **Write the baton** with proper YAML frontmatter:
SKILL.md:231In the instructionsOpen original file
| Method | How it works ||--------|--------------|| **CI/CD** | GitHub Actions triggers on `.stitch/next-prompt.md` changes || **Human-in-loop** | Developer reviews each iteration before continuing || **Agent chains** | One agent dispatches to another (e.g., Jules API) || **Manual** | Developer runs the agent repeatedly with the same repo |
SKILL.md:129In the instructionsOpen original file
### Step 6: Prepare the Next Baton (Critical)**You MUST update `.stitch/next-prompt.md` before completing.** This keeps the loop alive.1. **Decide the next page**:    - Check `.stitch/SITE.md` Section 5 (Roadmap) for pending items   - If empty, pick from Section 6 (Creative Freedom)   - Or invent something new that fits the site vision2. **Write the baton** with proper YAML frontmatter:
Could it bypass safety checks?Looks for skipped website security checks, excessive file access, or actions that skip your approval.Risks found: 1
Low risk

The install command does not pin a dependency version

Source references: 1
What we found

The installation command does not specify dependency versions. The same command may download different code later, so what you install can differ from what was checked.

Why this matters

A later install may download different code even though the command and this report have not changed.

The optional visual-verification step runs an unpinned `npx serve`. If the package is not already available, npx may download and execute the version resolved at that time, so later runs can use different code. This occurs only when optional browser verification is used; the user can require a pinned version or an already-audited local server.

SKILL.md:114In the instructionsOpen original file
1. **Check availability**: Run `list_tools` to see if `chrome*` tools are present2. **Start dev server**: Use Bash to start a local server (e.g., `npx serve site/public`)3. **Navigate to page**: Call `[chrome_prefix]:navigate` to open `http://localhost:3000/{page}.html`
Could it mislead the AI or hide text?Checks the skill instructions for requests to ignore you, influence the report, or hide text in invisible characters.Risks found: 1
Medium risk

Repository Markdown is treated as agent instruction and a source of authorization

Source references: 6
What we found

The Skill tells the agent to read baton, SITE, and DESIGN files and choose work from their contents. The supplied SITE example even contains an explicit “AGENT INSTRUCTION.” These files are not bounded as untrusted data, and there is no rule to ignore tool instructions unrelated to site design.

Why this matters

In an untrusted or collaborative repository, prompt injection hidden in these files could redirect the task, induce additional tool actions, or cause the agent to generate and integrate content the user did not approve.

Reading these project Markdown files is the skill's intended mechanism, but they are actively used as generation prompts and sources for task selection and subsequent decisions; the example explicitly labels SITE.md as an agent instruction. The visible text neither limits accepted content to site-building fields nor says to ignore additional tool directives. In an untrusted repository or baton, this creates prompt-injection and authorization risk. The user can require data-only parsing and separate approval for tool use or scope changes.

SKILL.md:63In the instructionsOpen original file
Parse `.stitch/next-prompt.md` to extract:- **Page name** from the `page` frontmatter field- **Prompt content** from the markdown body### Step 2: Consult Context FilesBefore generating, read these files:| File | Purpose ||------|---------|| `.stitch/SITE.md` | Site vision, **Stitch Project ID**, existing pages (sitemap), roadmap || `.stitch/DESIGN.md` | Required visual style for Stitch prompts |
Show 5 other places
examples/SITE.md:4In the instructionsOpen original file
---# Project Vision & Constitution> **AGENT INSTRUCTION:** Read this file before every iteration. It serves as the project's "Long-Term Memory." If `next-prompt.md` is empty, pick the highest priority item from Section 5 OR invent a new page that fits the project vision.
SKILL.md:4In the instructionsOpen original file
description: Teaches agents to iteratively build websites using Stitch with an autonomous baton-passing loop patternallowed-tools:  - "stitch*:*"  - "chrome*:*"  - "Read"  - "Write"  - "Bash"---
SKILL.md:90In the instructionsOpen original file
   - After generating each screen, call `[prefix]:get_project` again and update the `screens` map in `.stitch/metadata.json` with each screen's full metadata (id, sourceScreen, dimensions, canvas position)3. **Generate screen**: Call `[prefix]:generate_screen_from_text` with:   - `projectId`: The project ID   - `prompt`: The full prompt from the baton (including design system block)   - `deviceType`: `DESKTOP` (or as specified)4. **Retrieve assets**: Before downloading, check if `.stitch/designs/{page}.html` and `.stitch/designs/{page}.png` already exist:
SKILL.md:133In the instructionsOpen original file
1. **Decide the next page**:    - Check `.stitch/SITE.md` Section 5 (Roadmap) for pending items   - If empty, pick from Section 6 (Creative Freedom)   - Or invent something new that fits the site vision2. **Write the baton** with proper YAML frontmatter:
examples/SITE.md:6In the instructionsOpen original file
> **AGENT INSTRUCTION:** Read this file before every iteration. It serves as the project's "Long-Term Memory." If `next-prompt.md` is empty, pick the highest priority item from Section 5 OR invent a new page that fits the project vision.
Could it change links or payment recipients without asking?Looks for forced referral or payment changes combined with instructions to hide the change.No risks found

Inside this skill

8 instruction sections

The Skill reads baton, site-plan, and design files, sends the full baton content to Stitch to generate a page, and downloads the resulting HTML and screenshot.

View source
SKILL.md:63In the instructionsOpen original file
Parse `.stitch/next-prompt.md` to extract:- **Page name** from the `page` frontmatter field- **Prompt content** from the markdown body
SKILL.md:90In the instructionsOpen original file
   - After generating each screen, call `[prefix]:get_project` again and update the `screens` map in `.stitch/metadata.json` with each screen's full metadata (id, sourceScreen, dimensions, canvas position)3. **Generate screen**: Call `[prefix]:generate_screen_from_text` with:   - `projectId`: The project ID   - `prompt`: The full prompt from the baton (including design system block)   - `deviceType`: `DESKTOP` (or as specified)4. **Retrieve assets**: Before downloading, check if `.stitch/designs/{page}.html` and `.stitch/designs/{page}.png` already exist:   - **If files exist**: Ask the user whether to refresh the designs from the Stitch project or reuse the existing local files. Only re-download if the user confirms.   - **If files do not exist**: Proceed with download:     - `htmlCode.downloadUrl` — Download and save as `.stitch/designs/{page}.html`      - `screenshot.downloadUrl` — Append `=w{width}` to the URL before downloading, where `{width}` is the `width` value from the screen metadata (Google CDN serves low-res thumbnails by default). Save as `.stitch/designs/{page}.png`

Generated HTML is moved into the public site, and navigation plus headers and footers across pages may be changed. The optional workflow also renders that HTML in a local browser.

View source
SKILL.md:102In the instructionsOpen original file
1. Move generated HTML from `.stitch/designs/{page}.html` to `site/public/{page}.html`2. Fix any asset paths to be relative to the public folder3. Update navigation:   - Find existing placeholder links (e.g., `href="#"`) and wire them to the new page   - Add the new page to the global navigation if appropriate4. Ensure consistent headers/footers across all pages
SKILL.md:114In the instructionsOpen original file
1. **Check availability**: Run `list_tools` to see if `chrome*` tools are present2. **Start dev server**: Use Bash to start a local server (e.g., `npx serve site/public`)3. **Navigate to page**: Call `[chrome_prefix]:navigate` to open `http://localhost:3000/{page}.html`4. **Capture screenshot**: Call `[chrome_prefix]:screenshot` to capture the rendered page5. **Visual comparison**: Compare against the Stitch screenshot (`.stitch/designs/{page}.png`) for fidelity6. **Stop server**: Terminate the dev server process

The workflow is designed to continue: every iteration must write the next task, and the agent may choose or invent a page when the roadmap is empty. It can also be triggered by CI/CD changes to the baton file.

View source
SKILL.md:129In the instructionsOpen original file
### Step 6: Prepare the Next Baton (Critical)**You MUST update `.stitch/next-prompt.md` before completing.** This keeps the loop alive.1. **Decide the next page**:    - Check `.stitch/SITE.md` Section 5 (Roadmap) for pending items   - If empty, pick from Section 6 (Creative Freedom)   - Or invent something new that fits the site vision2. **Write the baton** with proper YAML frontmatter:
SKILL.md:231In the instructionsOpen original file
| Method | How it works ||--------|--------------|| **CI/CD** | GitHub Actions triggers on `.stitch/next-prompt.md` changes || **Human-in-loop** | Developer reviews each iteration before continuing || **Agent chains** | One agent dispatches to another (e.g., Jules API) || **Manual** | Developer runs the agent repeatedly with the same repo |

The installation instructions use an unpinned `npx` command and request a global Skill installation from a remote repository.

View source
README.md:5In the instructionsOpen original file
## Install```bashnpx skills add google-labs-code/stitch-skills --skill stitch-loop --global```
Start here · InstructionsSKILL.md
stitch-loop
Lines connect the instruction file to its sections, not an observed execution order. Select a section to read the source. 1 more sections are available in the original file.

File reference map

References: 1
Files making referencesReferenced content
Lines show actual file references, not execution order. Select a node to highlight its connections and inspect the files and source locations. Dashed lines include files that still need locating.
Files and check records6 files

Coverage and gaps

Content covered in each file

These are the source ranges included in this check, not a guarantee that every issue has been resolved.

  • SKILL.mdFull text included
  • examples/next-prompt.mdFull text included
  • examples/SITE.mdFull text included
  • README.mdFull text included
  • resources/baton-schema.mdFull text included
  • resources/site-template.mdFull text included

This report is for the version above. We read the available code and instructions without running the skill or checking extra packages it installs. This is not a promise of safety: a different version or setup may behave differently.

  • README.mdSupporting file
  • SKILL.mdInstructions
  • examples/SITE.mdSupporting file
  • examples/next-prompt.mdSupporting file
  • resources/baton-schema.mdSupporting file
  • resources/site-template.mdSupporting file

Operations mentioned in code and instructions

Run commands
README.md:7In the instructionsOpen original file
```bashnpx skills add google-labs-code/stitch-skills --skill stitch-loop --global
SKILL.md:9In the instructionsOpen original file
  - "Write"  - "Bash"---
SKILL.md:114In the instructionsOpen original file
1. **Check availability**: Run `list_tools` to see if `chrome*` tools are present2. **Start dev server**: Use Bash to start a local server (e.g., `npx serve site/public`)3. **Navigate to page**: Call `[chrome_prefix]:navigate` to open `http://localhost:3000/{page}.html`
Install extra software packages
README.md:8In the instructionsOpen original file
```bashnpx skills add google-labs-code/stitch-skills --skill stitch-loop --global```
SKILL.md:114In the instructionsOpen original file
1. **Check availability**: Run `list_tools` to see if `chrome*` tools are present2. **Start dev server**: Use Bash to start a local server (e.g., `npx serve site/public`)3. **Navigate to page**: Call `[chrome_prefix]:navigate` to open `http://localhost:3000/{page}.html`
Read files
SKILL.md:69In the instructionsOpen original file
Before generating, read these files:
examples/SITE.md:6In the instructionsOpen original file
> **AGENT INSTRUCTION:** Read this file before every iteration. It serves as the project's "Long-Term Memory." If `next-prompt.md` is empty, pick the highest priority item from Section 5 OR invent a new page that fits the project vision.
resources/site-template.md:10In the instructionsOpen original file
> **AGENT INSTRUCTION:** Read this file before every iteration. It serves as the project's "Long-Term Memory."
Connect to websites
SKILL.md:115In the instructionsOpen original file
2. **Start dev server**: Use Bash to start a local server (e.g., `npx serve site/public`)3. **Navigate to page**: Call `[chrome_prefix]:navigate` to open `http://localhost:3000/{page}.html`4. **Capture screenshot**: Call `[chrome_prefix]:screenshot` to capture the rendered page
Lines read
586
File checksum (to compare versions)
c5e03f731e6de2f0a206f749b054430a7dbb63ab989712449a5e3d75eff01199