Skip to content

🚨 [security] Update @astrojs/cloudflare 12.6.13 → 13.7.0 (major) - #456

Closed
depfu[bot] wants to merge 3 commits into
mainfrom
depfu/update/npm/@astrojs/cloudflare-13.7.0
Closed

🚨 [security] Update @astrojs/cloudflare 12.6.13 → 13.7.0 (major)#456
depfu[bot] wants to merge 3 commits into
mainfrom
depfu/update/npm/@astrojs/cloudflare-13.7.0

Conversation

@depfu

@depfu depfu Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Superseded by #452, which upgrades @astrojs/cloudflare to 13.7.0 as part
of the Astro 6 upgrade. Closing in favor of that PR.


🚨 Your current dependencies have known security vulnerabilities 🚨

This dependency update fixes known security vulnerabilities. Please see the details below and assess their impact carefully. We recommend to merge and deploy this as soon as possible!


Here is everything you need to know about this upgrade. Please take a good look at what changed and the test results before merging this pull request.

What changed?

✳️ @​astrojs/cloudflare (12.6.13 → 13.7.0) · Repo · Changelog

Security Advisories 🚨

🚨 Cloudflare has SSRF via redirect following through its image-binding-transform endpoint (incomplete fix for GHSA-qpr4)

Summary

The fetch() call for remote images in packages/integrations/cloudflare/src/utils/image-binding-transform.ts (line 28) uses the default redirect: 'follow' behavior. This allows the Cloudflare Worker to follow HTTP redirects to arbitrary URLs, bypassing the isRemoteAllowed() domain allowlist check which only validates the initial URL.

All three other image fetch paths in the codebase correctly use { redirect: 'manual' }. This is an incomplete fix for GHSA-qpr4-c339-7vq8.

Confirmed on HEAD.

Root Cause

image-binding-transform.ts line 28:

const content = await (isRemotePath(href) ? fetch(imageSrc) : assets.fetch(imageSrc));

Missing { redirect: 'manual' }. The three protected paths:

// image-passthrough-endpoint.ts:23
response = await fetch(href, { redirect: 'manual' });

// assets/endpoint/shared.ts:11
const res = await fetch(src, { redirect: 'manual' });

// assets/utils/remoteProbe.ts:53
const response = await fetch(url, { redirect: 'manual' });

PoC

Demonstrated with Node.js that fetch() without redirect: 'manual' follows 302 redirects to arbitrary destinations:

# Server A (allowed domain) returns 302 → Server B (internal)
fetch('http://allowed:19741/img.jpg')                        → follows 302 → hits http://internal:19742/secret
fetch('http://allowed:19741/img.jpg', {redirect:'manual'})   → returns 302, internal server NOT hit

Attack path: attacker finds an open redirect on an allowed domain, crafts /_image?href=https://allowed-cdn.com/redirect?url=http://internal-service/, and the Worker follows the redirect to the unauthorized destination.

Impact

Bypasses the image.domains and image.remotePatterns allowlist for the default Cloudflare image service (cloudflare-binding). Enables blind SSRF to domains not in the allowlist. Same vulnerability class as GHSA-qpr4-c339-7vq8 (HIGH) which fixed the passthrough endpoint but missed this one.

Suggested Fix

const content = await (isRemotePath(href) ? fetch(imageSrc, { redirect: 'manual' }) : assets.fetch(imageSrc));

🆕 @​cloudflare/vite-plugin (added, 1.42.4)

🆕 @​shikijs/primitive (added, 4.3.0)

🆕 @​cloudflare/workerd-darwin-64 (added, 1.20260630.1)

🆕 @​cloudflare/workerd-darwin-arm64 (added, 1.20260630.1)

🆕 @​cloudflare/workerd-linux-64 (added, 1.20260630.1)

🆕 @​cloudflare/workerd-linux-arm64 (added, 1.20260630.1)

🆕 @​cloudflare/workerd-windows-64 (added, 1.20260630.1)

🆕 @​esbuild/aix-ppc64 (added, 0.28.1)

🆕 @​esbuild/android-arm (added, 0.28.1)

🆕 @​esbuild/android-arm64 (added, 0.28.1)

🆕 @​esbuild/android-x64 (added, 0.28.1)

🆕 @​esbuild/darwin-arm64 (added, 0.28.1)

🆕 @​esbuild/darwin-x64 (added, 0.28.1)

🆕 @​esbuild/freebsd-arm64 (added, 0.28.1)

🆕 @​esbuild/freebsd-x64 (added, 0.28.1)

🆕 @​esbuild/linux-arm (added, 0.28.1)

🆕 @​esbuild/linux-arm64 (added, 0.28.1)

🆕 @​esbuild/linux-ia32 (added, 0.28.1)

🆕 @​esbuild/linux-loong64 (added, 0.28.1)

🆕 @​esbuild/linux-mips64el (added, 0.28.1)

🆕 @​esbuild/linux-ppc64 (added, 0.28.1)

🆕 @​esbuild/linux-riscv64 (added, 0.28.1)

🆕 @​esbuild/linux-s390x (added, 0.28.1)

🆕 @​esbuild/linux-x64 (added, 0.28.1)

🆕 @​esbuild/netbsd-arm64 (added, 0.28.1)

🆕 @​esbuild/netbsd-x64 (added, 0.28.1)

🆕 @​esbuild/openbsd-arm64 (added, 0.28.1)

🆕 @​esbuild/openbsd-x64 (added, 0.28.1)

🆕 @​esbuild/openharmony-arm64 (added, 0.28.1)

🆕 @​esbuild/sunos-x64 (added, 0.28.1)

🆕 @​esbuild/win32-arm64 (added, 0.28.1)

🆕 @​esbuild/win32-ia32 (added, 0.28.1)

🆕 @​esbuild/win32-x64 (added, 0.28.1)

🆕 esbuild (added, 0.28.1)

🆕 miniflare (added, 4.20260630.0)

🆕 undici (added, 7.28.0)

🆕 workerd (added, 1.20260630.1)

🆕 wrangler (added, 4.106.0)

🆕 ws (added, 8.21.0)

🆕 @​astrojs/internal-helpers (added, 0.10.0)

🆕 @​shikijs/core (added, 4.3.0)

🆕 @​shikijs/engine-javascript (added, 4.3.0)

🆕 @​shikijs/engine-oniguruma (added, 4.3.0)

🆕 @​shikijs/langs (added, 4.3.0)

🆕 @​shikijs/themes (added, 4.3.0)

🆕 @​shikijs/types (added, 4.3.0)

🆕 shiki (added, 4.3.0)

🆕 vite (added, 7.3.6)

🗑️ @​cloudflare/workers-types (removed)

🗑️ @​cloudflare/kv-asset-handler (removed)

🗑️ @​cloudflare/unenv-preset (removed)

🗑️ @​cloudflare/workerd-darwin-64 (removed)

🗑️ @​cloudflare/workerd-darwin-64 (removed)

🗑️ @​cloudflare/workerd-darwin-arm64 (removed)

🗑️ @​cloudflare/workerd-darwin-arm64 (removed)

🗑️ @​cloudflare/workerd-linux-64 (removed)

🗑️ @​cloudflare/workerd-linux-64 (removed)

🗑️ @​cloudflare/workerd-linux-arm64 (removed)

🗑️ @​cloudflare/workerd-linux-arm64 (removed)

🗑️ @​cloudflare/workerd-windows-64 (removed)

🗑️ @​cloudflare/workerd-windows-64 (removed)

🗑️ @​esbuild/aix-ppc64 (removed)

🗑️ @​esbuild/aix-ppc64 (removed)

🗑️ @​esbuild/android-arm (removed)

🗑️ @​esbuild/android-arm (removed)

🗑️ @​esbuild/android-arm64 (removed)

🗑️ @​esbuild/android-arm64 (removed)

🗑️ @​esbuild/android-x64 (removed)

🗑️ @​esbuild/android-x64 (removed)

🗑️ @​esbuild/darwin-arm64 (removed)

🗑️ @​esbuild/darwin-arm64 (removed)

🗑️ @​esbuild/darwin-x64 (removed)

🗑️ @​esbuild/darwin-x64 (removed)

🗑️ @​esbuild/freebsd-arm64 (removed)

🗑️ @​esbuild/freebsd-arm64 (removed)

🗑️ @​esbuild/freebsd-x64 (removed)

🗑️ @​esbuild/freebsd-x64 (removed)

🗑️ @​esbuild/linux-arm (removed)

🗑️ @​esbuild/linux-arm (removed)

🗑️ @​esbuild/linux-arm64 (removed)

🗑️ @​esbuild/linux-arm64 (removed)

🗑️ @​esbuild/linux-ia32 (removed)

🗑️ @​esbuild/linux-ia32 (removed)

🗑️ @​esbuild/linux-loong64 (removed)

🗑️ @​esbuild/linux-loong64 (removed)

🗑️ @​esbuild/linux-mips64el (removed)

🗑️ @​esbuild/linux-mips64el (removed)

🗑️ @​esbuild/linux-ppc64 (removed)

🗑️ @​esbuild/linux-ppc64 (removed)

🗑️ @​esbuild/linux-riscv64 (removed)

🗑️ @​esbuild/linux-riscv64 (removed)

🗑️ @​esbuild/linux-s390x (removed)

🗑️ @​esbuild/linux-s390x (removed)

🗑️ @​esbuild/linux-x64 (removed)

🗑️ @​esbuild/linux-x64 (removed)

🗑️ @​esbuild/netbsd-arm64 (removed)

🗑️ @​esbuild/netbsd-arm64 (removed)

🗑️ @​esbuild/netbsd-x64 (removed)

🗑️ @​esbuild/netbsd-x64 (removed)

🗑️ @​esbuild/openbsd-arm64 (removed)

🗑️ @​esbuild/openbsd-arm64 (removed)

🗑️ @​esbuild/openbsd-x64 (removed)

🗑️ @​esbuild/openbsd-x64 (removed)

🗑️ @​esbuild/openharmony-arm64 (removed)

🗑️ @​esbuild/openharmony-arm64 (removed)

🗑️ @​esbuild/sunos-x64 (removed)

🗑️ @​esbuild/sunos-x64 (removed)

🗑️ @​esbuild/win32-arm64 (removed)

🗑️ @​esbuild/win32-arm64 (removed)

🗑️ @​esbuild/win32-ia32 (removed)

🗑️ @​esbuild/win32-ia32 (removed)

🗑️ @​esbuild/win32-x64 (removed)

🗑️ @​esbuild/win32-x64 (removed)

🗑️ esbuild (removed)

🗑️ esbuild (removed)

🗑️ miniflare (removed)

🗑️ miniflare (removed)

🗑️ undici (removed)

🗑️ undici (removed)

🗑️ undici (removed)

🗑️ workerd (removed)

🗑️ workerd (removed)

🗑️ wrangler (removed)

🗑️ wrangler (removed)

🗑️ ws (removed)

🗑️ ws (removed)

🗑️ typescript (removed)


Depfu Status

Depfu will automatically keep this PR conflict-free, as long as you don't add any commits to this branch yourself. You can also trigger a rebase manually by commenting with @depfu rebase.

All Depfu comment commands
@​depfu rebase
Rebases against your default branch and redoes this update
@​depfu recreate
Recreates this PR, overwriting any edits that you've made to it
@​depfu merge
Merges this PR once your tests are passing and conflicts are resolved
@​depfu cancel merge
Cancels automatic merging of this PR
@​depfu close
Closes this PR and deletes the branch
@​depfu reopen
Restores the branch and reopens this PR (if it's closed)
@​depfu pause
Ignores all future updates for this dependency and closes this PR
@​depfu pause [minor|major]
Ignores all future minor/major updates for this dependency and closes this PR
@​depfu resume
Future versions of this dependency will create PRs again (leaves this PR as is)

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 25, 2026

Copy link
Copy Markdown

Deploying head-start with  Cloudflare Pages  Cloudflare Pages

Latest commit: d6875cc
Status:🚫  Build failed.

View logs

@depfu depfu Bot added the depfu label Jun 25, 2026
@depfu
depfu Bot force-pushed the depfu/update/npm/@astrojs/cloudflare-13.7.0 branch 3 times, most recently from c90eda0 to 7c04d11 Compare July 2, 2026 09:20
@MarleenEliza
MarleenEliza force-pushed the depfu/update/npm/@astrojs/cloudflare-13.7.0 branch from 7c04d11 to d6875cc Compare July 3, 2026 13:06
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 3, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
head-start-worker d6875cc Jul 03 2026, 01:06 PM

MarleenEliza pushed a commit that referenced this pull request Jul 28, 2026
## Upgrade to Astro 6

> Supersedes #456 — this upgrade already bumps `@astrojs/cloudflare` to
13.7.0
> (the security fix in #456) as part of the Astro 6 major upgrade, so
#456 can
> be closed once this merges.

Bumps Astro to `^6.4.8` and migrates the codebase per the [official v5 →
v6 guide](https://docs.astro.build/en/guides/upgrade-to/v6/). The
initial dependency bump broke CI (`ERESOLVE` peer conflict); this PR
carries the full set of migration changes needed to get green.

### Changes

**Dependencies**
- `@astrojs/cloudflare` `^12.6.7` → `^13.7.0` — v13 is the release that
peers `astro@^6` (this was the root cause of the failing `npm ci`).

**Content collections**
- Moved `src/content/config.ts` → `src/content.config.ts` (v6 required
location) and updated importers (`src/lib/content/*`). Collections
already used the Content Layer `loader` API, so no data-layer migration
was needed.

**Config (`astro.config.ts`)**
- Moved `fonts` out of `experimental` (now a stable top-level option).
- Removed the `platformProxy` adapter option (removed in adapter v13;
the Cloudflare Vite plugin handles local bindings automatically).
- Skip the Cloudflare adapter under Vitest — v13's Vite plugin rejects
the Node `resolve.external` list Astro sets on the SSR env, which
otherwise breaks `getViteConfig` in tests.
- Load `.env` via `loadEnv` into the `astro:env` defaults so local `npm
run build` works from `.env` alone.
  Otherwise:
<img width="1211" height="272" alt="image"
src="https://github.com/user-attachments/assets/2cad7669-8263-4fb2-875f-6c00b1f3bf29"
/>


**Cloudflare / Workers**
- `wrangler.toml` `main` → `@astrojs/cloudflare/entrypoints/server` (v13
entrypoint).
- Fixed the postbuild readme cleanup path for the new `dist/client/`
static output layout.

**Service worker (dev)**
- Serve `/service-worker.js` in dev via a Vite dev-server middleware
instead of an on-demand route. Since v13 runs dev routes in Cloudflare's
`workerd` runtime, running esbuild inside the request handler crashed
with `__filename is not defined`. Vite middleware runs in Node, so
esbuild works there. Production (`astro:build:done`) is unchanged.

### Verification

- `npm ci` resolves cleanly
-`lint:eslint`, `lint:astro` (0 errors)
- `test:unit` — 243 passed
- `npm run build` completes; prerenders all routes
- `lint:html` — 0 errors
- `wrangler deploy --dry-run` — bindings resolve, assets read from
`dist/client`
- `astro dev` — pages + `/service-worker.js` serve correctly



------

🚨 <b>Your current dependencies have known security vulnerabilities</b> 🚨

This dependency update fixes known security vulnerabilities. Please see
the details below and assess their impact carefully. We recommend to
merge and deploy this as soon as possible!
<hr>



Here is everything you need to know about this upgrade. Please take a
good look at what changed and the test results before merging this pull
request.

### What changed?




#### ✳️ astro (5.18.2 → 6.4.8) ·
[Repo](https://github.com/withastro/astro) ·
[Changelog](https://github.com/withastro/astro/blob/main/packages/astro/CHANGELOG.md)


<details>

<summary>Security Advisories 🚨</summary>
<h4><a
href="https://bounce.depfu.com/github.com/withastro/astro/security/advisories/GHSA-8hv8-536x-4wqp">🚨
Astro: Reflected XSS via unescaped slot name</a></h4>
<blockquote><h2 dir="auto">Summary</h2>
<p dir="auto">When a component uses a <code
class="notranslate">client:*</code> directive, Astro inserts named slot
content into a <code class="notranslate">data-astro-template</code>
attribute without HTML escaping the slot name allowing an attacker to
break out of the attribute context and inject arbitrary HTML, resulting
in reflected XSS during SSR.</p>
<p dir="auto">This is similar to <a
href="https://bounce.depfu.com/github.com/advisories/GHSA-wrwg-2hg8-v723">GHSA-wrwg-2hg8-v723</a>
but exploits a different injection point.</p>
<h2 dir="auto">Vulnerable Code</h2>
<p dir="auto"><code
class="notranslate">packages/astro/src/runtime/server/render/component.ts:371:376</code></p>
<div class="highlight highlight-source-ts" dir="auto"><pre
class="notranslate"><span class="pl-c">// component.ts:371</span>
<span class="pl-s">`&lt;template data-astro-template<span
class="pl-s1"><span class="pl-kos">${</span><span
class="pl-s1">key</span> <span class="pl-c1">!==</span> <span
class="pl-s">'default'</span> ? <span class="pl-s">`="<span
class="pl-s1"><span class="pl-kos">${</span><span
class="pl-s1">key</span><span class="pl-kos">}</span></span>"`</span> :
<span class="pl-s">''</span><span
class="pl-kos">}</span></span>&gt;<span class="pl-s1"><span
class="pl-kos">${</span><span class="pl-s1">children</span><span
class="pl-kos">[</span><span class="pl-s1">key</span><span
class="pl-kos">]</span><span
class="pl-kos">}</span></span>&lt;/template&gt;`</span></pre></div>
<p dir="auto">I found that key is interpolated directly into the
attribute value without proper escaping.</p>
<h2 dir="auto">Proof of Concept</h2>
<p dir="auto">For the PoC, I set up with a minimal repository with Astro
6.3.1, Node.js: v26.0.0.</p>
<p dir="auto"><strong><code
class="notranslate">astro.config.mjs</code></strong></p>
<div class="highlight highlight-source-js" dir="auto"><pre
class="notranslate"><span class="pl-k">import</span> <span
class="pl-s1">react</span> <span class="pl-k">from</span> <span
class="pl-s">'@astrojs/react'</span><span class="pl-kos">;</span>
<span class="pl-k">import</span> <span class="pl-s1">node</span> <span
class="pl-k">from</span> <span class="pl-s">'@astrojs/node'</span><span
class="pl-kos">;</span>
<span class="pl-k">import</span> <span class="pl-kos">{</span> <span
class="pl-s1">defineConfig</span> <span class="pl-kos">}</span> <span
class="pl-k">from</span> <span class="pl-s">'astro/config'</span><span
class="pl-kos">;</span>
<span class="pl-k">export</span> <span class="pl-k">default</span> <span
class="pl-en">defineConfig</span><span class="pl-kos">(</span><span
class="pl-kos">{</span>
<span class="pl-c1">output</span>: <span
class="pl-s">'server'</span><span class="pl-kos">,</span>
<span class="pl-c1">adapter</span>: <span class="pl-en">node</span><span
class="pl-kos">(</span><span class="pl-kos">{</span> <span
class="pl-c1">mode</span>: <span class="pl-s">'standalone'</span> <span
class="pl-kos">}</span><span class="pl-kos">)</span><span
class="pl-kos">,</span>
<span class="pl-c1">integrations</span>: <span
class="pl-kos">[</span><span class="pl-en">react</span><span
class="pl-kos">(</span><span class="pl-kos">)</span><span
class="pl-kos">]</span><span class="pl-kos">,</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span
class="pl-kos">;</span></pre></div>
<p dir="auto"><strong><code
class="notranslate">src/pages/index.astro</code></strong></p>
<div class="highlight highlight-source-astro" dir="auto"><pre
class="notranslate"><span class="pl-c">---</span><span
class="pl-s1"></span>
<span class="pl-s1"><span class="pl-k">import</span> <span
class="pl-smi">Wrapper</span> <span class="pl-k">from</span> <span
class="pl-s"><span class="pl-pds">'</span>../components/Wrapper.jsx<span
class="pl-pds">'</span></span>;</span>
<span class="pl-s1"><span class="pl-k"><span
class="pl-k">const</span></span> slotName <span class="pl-k">=</span>
<span class="pl-smi">Astro</span>.<span class="pl-smi">url</span>.<span
class="pl-smi">searchParams</span>.<span class="pl-c1">get</span>(<span
class="pl-s"><span class="pl-pds">'</span>tab<span
class="pl-pds">'</span></span>) <span class="pl-k">??</span> <span
class="pl-s"><span class="pl-pds">'</span>default<span
class="pl-pds">'</span></span>;</span>
<span class="pl-s1"></span><span class="pl-c">---</span>
&lt;<span class="pl-ent">html</span>&gt;&lt;<span
class="pl-ent">body</span>&gt;
&lt;<span class="pl-c1">Wrapper</span> <span
class="pl-e">client:load</span>&gt;
&lt;<span class="pl-ent">div</span> <span class="pl-e">slot</span>=<span
class="pl-pse">{</span><span class="pl-smi">slotName</span><span
class="pl-pse">}</span>&gt;content&lt;/<span
class="pl-ent">div</span>&gt;
  &lt;/<span class="pl-c1">Wrapper</span>&gt;
&lt;/<span class="pl-ent">body</span>&gt;&lt;/<span
class="pl-ent">html</span>&gt;</pre></div>
<p dir="auto"><strong><code
class="notranslate">src/components/Wrapper.jsx</code></strong></p>
<div class="highlight highlight-source-js" dir="auto"><pre
class="notranslate"><span class="pl-k">export</span> <span
class="pl-k">default</span> <span class="pl-k">function</span> <span
class="pl-v">Wrapper</span><span class="pl-kos">(</span><span
class="pl-kos">)</span> <span class="pl-kos">{</span> <span
class="pl-k">return</span> <span class="pl-c1">null</span><span
class="pl-kos">;</span> <span class="pl-kos">}</span></pre></div>
<p dir="auto"><strong>Payload:</strong></p>
<pre class="notranslate"><code
class="notranslate">abc"&gt;&lt;/template&gt;&lt;/astro-island&gt;&lt;img
src=x onerror=confirm(document.domain)&gt;&lt;!--
</code></pre>
<p dir="auto">Accessing this URL will trigger the popup.</p>
<p dir="auto"><a
href="http://localhost:4321/?tab=abc%22%3E%3C%2Ftemplate%3E%3C%2Fastro-island%3E%3Cimg+src%3Dx+onerror%3Dconfirm(document.domain)%3E%3C!--">http://localhost:4321/?tab=abc%22%3E%3C%2Ftemplate%3E%3C%2Fastro-island%3E%3Cimg+src%3Dx+onerror%3Dconfirm(document.domain)%3E%3C!--</a></p>
<a
href="https://private-user-images.githubusercontent.com/45068820/590345346-675cdc04-4134-4d83-883c-abe16d751ec7.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODE2MjU5MDUsIm5iZiI6MTc4MTYyNTYwNSwicGF0aCI6Ii80NTA2ODgyMC81OTAzNDUzNDYtNjc1Y2RjMDQtNDEzNC00ZDgzLTg4M2MtYWJlMTZkNzUxZWM3LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA2MTYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwNjE2VDE2MDAwNVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTI1MWI4NjU2Nzk4NjAyYjFiZTFlNTQzM2VjZDgwOTA2MmU4Y2ZkZjhhMjZiNWEyMzJmM2RmMzhmNDY1NTg4MDMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.jIUAmkwqqW4rEuonsAXIRIG6jrM0dMs-LmyTiKTvP5s"><img
width="1268" height="592" alt="image"
src="https://private-user-images.githubusercontent.com/45068820/590345346-675cdc04-4134-4d83-883c-abe16d751ec7.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODE2MjU5MDUsIm5iZiI6MTc4MTYyNTYwNSwicGF0aCI6Ii80NTA2ODgyMC81OTAzNDUzNDYtNjc1Y2RjMDQtNDEzNC00ZDgzLTg4M2MtYWJlMTZkNzUxZWM3LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA2MTYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwNjE2VDE2MDAwNVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTI1MWI4NjU2Nzk4NjAyYjFiZTFlNTQzM2VjZDgwOTA2MmU4Y2ZkZjhhMjZiNWEyMzJmM2RmMzhmNDY1NTg4MDMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.jIUAmkwqqW4rEuonsAXIRIG6jrM0dMs-LmyTiKTvP5s"
style="max-width: 100%; height: auto; max-height: 592px;; aspect-ratio:
1268 / 592; background-color: var(--bgColor-muted); border-radius: 6px"
class="js-gh-image-fallback"></a>
<p dir="auto">This will render in html.</p>
<div class="highlight highlight-text-html-basic" dir="auto"><pre
class="notranslate"><span class="pl-kos">&lt;</span><span
class="pl-ent">template</span> <span
class="pl-c1">data-astro-template</span>="<span
class="pl-s">abc</span>"<span class="pl-kos">&gt;</span><span
class="pl-kos">&lt;/</span><span class="pl-ent">template</span><span
class="pl-kos">&gt;</span><span
class="pl-kos">&lt;/</span>astro-island<span class="pl-kos">&gt;</span>
<span class="pl-kos">&lt;</span><span class="pl-ent">img</span> <span
class="pl-c1">src</span>=<span class="pl-s">x</span> <span
class="pl-c1">onerror</span>=<span
class="pl-s">confirm(document.domain)</span><span
class="pl-kos">&gt;</span>&lt;!--"<span
class="pl-kos">&gt;</span>content<span class="pl-kos">&lt;/</span><span
class="pl-ent">template</span><span
class="pl-kos">&gt;</span></pre></div>
<h2 dir="auto">Fix</h2>
<p dir="auto">I suggest leveraging the existing escape function on the
slot name.</p>
<div class="highlight highlight-source-ts" dir="auto"><pre
class="notranslate"><span class="pl-c">// component.ts:371</span>
<span class="pl-s">`&lt;template data-astro-template<span
class="pl-s1"><span class="pl-kos">${</span><span
class="pl-s1">key</span> <span class="pl-c1">!==</span> <span
class="pl-s">'default'</span> ? <span class="pl-s">`="<span
class="pl-s1"><span class="pl-kos">${</span><span
class="pl-en">escapeHTML</span><span class="pl-kos">(</span><span
class="pl-v">String</span><span class="pl-kos">(</span><span
class="pl-s1">key</span><span class="pl-kos">)</span><span
class="pl-kos">)</span><span class="pl-kos">}</span></span>"`</span> :
<span class="pl-s">''</span><span
class="pl-kos">}</span></span>&gt;<span class="pl-s1"><span
class="pl-kos">${</span><span class="pl-s1">children</span><span
class="pl-kos">[</span><span class="pl-s1">key</span><span
class="pl-kos">]</span><span
class="pl-kos">}</span></span>&lt;/template&gt;`</span></pre></div>
<hr></blockquote>
<h4><a
href="https://bounce.depfu.com/github.com/withastro/astro/security/advisories/GHSA-2pvr-wf23-7pc7">🚨
Astro: Host header SSRF in prerendered error page fetch</a></h4>
<blockquote><h2 dir="auto">Summary</h2>
<p dir="auto">Astro SSR apps with prerendered error pages (<code
class="notranslate">/404</code> or <code class="notranslate">/500</code>
using <code class="notranslate">export const prerender = true</code>)
fetch those pages over HTTP at runtime when an error occurs. The URL for
this fetch is derived from <code class="notranslate">request.url</code>,
which in turn gets its origin from the incoming <code
class="notranslate">Host</code> header. When the <code
class="notranslate">Host</code> header is not validated against <code
class="notranslate">allowedDomains</code>, an attacker can point the
fetch at an arbitrary host and read the response.</p>
<h2 dir="auto">Who is affected</h2>
<p dir="auto">This affects SSR deployments that:</p>
<ol dir="auto">
<li>Have a prerendered 404 or 500 page</li>
<li>Use <code class="notranslate">createRequestFromNodeRequest</code>
from <code class="notranslate">astro/app/node</code> with <code
class="notranslate">app.render()</code> <strong>without</strong>
overriding <code class="notranslate">prerenderedErrorPageFetch</code> —
this includes custom servers built on the public API and third-party
adapters</li>
</ol>
<p dir="auto"><strong>Not affected:</strong></p>
<ul dir="auto">
<li>
<code class="notranslate">@astrojs/node</code> &gt;= 9.5.4 (reads error
pages from disk)</li>
<li>
<code class="notranslate">@astrojs/cloudflare</code> (uses the ASSETS
binding)</li>
<li>The dev server (renders error pages in-process)</li>
</ul>
<h2 dir="auto">How it works</h2>
<p dir="auto"><code
class="notranslate">createRequestFromNodeRequest</code> builds <code
class="notranslate">request.url</code> from the raw <code
class="notranslate">Host</code> / <code
class="notranslate">:authority</code> header. The <code
class="notranslate">allowedDomains</code> option is accepted but only
gates <code class="notranslate">X-Forwarded-For</code> — it does not
constrain the URL origin. (The public <code
class="notranslate">createRequest</code> does fall back to <code
class="notranslate">localhost</code> for unvalidated hosts; this
internal builder did not.)</p>
<p dir="auto">When <code class="notranslate">app.render()</code>
encounters a 404 or 500 with a prerendered error route, <code
class="notranslate">default-handler.ts</code> constructs the error page
URL using the origin from <code class="notranslate">request.url</code>
and fetches it via <code
class="notranslate">prerenderedErrorPageFetch</code>, which defaults to
global <code class="notranslate">fetch</code>. The response body is
served to the client.</p>
<p dir="auto">An attacker sends a request with <code
class="notranslate">Host: attacker-host:port</code>, triggers an error
(e.g., requesting a nonexistent path for a 404), and receives the
response from the attacker-controlled host reflected back.</p>
<h2 dir="auto">Remediation</h2>
<p dir="auto">The error page fetch origin is now validated against <code
class="notranslate">allowedDomains</code> before use. When the host is
validated, the original origin is preserved. Otherwise, it falls back to
<code class="notranslate">localhost</code>. The fetch is also wrapped in
a try/catch so that connection failures degrade gracefully to a plain
error response.</p>
<h2 dir="auto">Credit</h2>
<p dir="auto">5ud0 / Tarmo Technologies</p></blockquote>
<h4><a
href="https://bounce.depfu.com/github.com/withastro/astro/security/advisories/GHSA-jrpj-wcv7-9fh9">🚨
Astro: XSS via Unescaped Attribute Names in Spread Props</a></h4>
<blockquote><h2 dir="auto">Summary</h2>
<p dir="auto">The <code class="notranslate">spreadAttributes</code>
function in Astro's server-side rendering pipeline iterates over object
keys and passes them directly to <code
class="notranslate">addAttribute</code>, which interpolates the key into
the HTML output without escaping. When a developer uses the spread
syntax <code class="notranslate">{...props}</code> on an HTML element
and the object keys come from an untrusted source (API, CMS, URL
parameters), an attacker can inject arbitrary HTML attributes including
event handlers like <code class="notranslate">onmousemove</code>, <code
class="notranslate">onclick</code>, or break out of the attribute
context entirely to inject new elements.</p>
<h2 dir="auto">Details</h2>
<p dir="auto">The vulnerable function is <a
href="https://bounce.depfu.com/github.com/withastro/astro/blob/main/packages/astro/src/runtime/server/render/util.ts#L81-L141"><code
class="notranslate">addAttribute</code></a> at <code
class="notranslate">packages/astro/src/runtime/server/render/util.ts:81-141</code>:</p>
<div class="highlight highlight-source-js" dir="auto"><pre
class="notranslate"><span class="pl-k">export</span> <span
class="pl-k">function</span> <span
class="pl-en">addAttribute</span><span class="pl-kos">(</span><span
class="pl-s1">value</span>: <span class="pl-s1">any</span><span
class="pl-kos">,</span> <span class="pl-s1">key</span>: <span
class="pl-s1">string</span><span class="pl-kos">,</span> <span
class="pl-s1">shouldEscape</span> <span class="pl-c1">=</span> <span
class="pl-c1">true</span><span class="pl-kos">,</span> <span
class="pl-s1">tagName</span> <span class="pl-c1">=</span> <span
class="pl-s">''</span><span class="pl-kos">)</span> <span
class="pl-kos">{</span>
<span class="pl-k">if</span> <span class="pl-kos">(</span><span
class="pl-s1">value</span> <span class="pl-c1">==</span> <span
class="pl-c1">null</span><span class="pl-kos">)</span> <span
class="pl-kos">{</span>
<span class="pl-k">return</span> <span class="pl-s">''</span><span
class="pl-kos">;</span>
    <span class="pl-kos">}</span>
    
<span class="pl-k">return</span> <span
class="pl-en">markHTMLString</span><span class="pl-kos">(</span><span
class="pl-s">` <span class="pl-s1"><span class="pl-kos">${</span><span
class="pl-s1">key</span><span class="pl-kos">}</span></span>="<span
class="pl-s1"><span class="pl-kos">${</span><span
class="pl-en">toAttributeString</span><span class="pl-kos">(</span><span
class="pl-s1">value</span><span class="pl-kos">,</span> <span
class="pl-s1">shouldEscape</span><span class="pl-kos">)</span><span
class="pl-kos">}</span></span>"`</span><span
class="pl-kos">)</span><span class="pl-kos">;</span> <span
class="pl-c">// key interpolated not escaped</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">This function is called from <a
href="https://bounce.depfu.com/github.com/withastro/astro/blob/main/packages/astro/src/runtime/server/index.ts#L91-L92"><code
class="notranslate">spreadAttributes</code></a> at <code
class="notranslate">packages/astro/src/runtime/server/index.ts:91-92</code>:</p>
<div class="highlight highlight-source-js" dir="auto"><pre
class="notranslate"><span class="pl-k">for</span> <span
class="pl-kos">(</span><span class="pl-k">const</span> <span
class="pl-kos">[</span><span class="pl-s1">key</span><span
class="pl-kos">,</span> <span class="pl-s1">value</span><span
class="pl-kos">]</span> <span class="pl-k">of</span> <span
class="pl-v">Object</span><span class="pl-kos">.</span><span
class="pl-en">entries</span><span class="pl-kos">(</span><span
class="pl-s1">values</span><span class="pl-kos">)</span><span
class="pl-kos">)</span> <span class="pl-kos">{</span>
<span class="pl-s1">output</span> <span class="pl-c1">+=</span> <span
class="pl-en">addAttribute</span><span class="pl-kos">(</span><span
class="pl-s1">value</span><span class="pl-kos">,</span> <span
class="pl-s1">key</span><span class="pl-kos">,</span> <span
class="pl-c1">true</span><span class="pl-kos">,</span> <span
class="pl-s1">_name</span><span class="pl-kos">)</span><span
class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">The <code class="notranslate">toAttributeString</code>
function escapes the attribute value, but the attribute name <code
class="notranslate">key</code> is never validated or escaped. An
attacker can craft a JSON object with a key containing " characters to
break out of the attribute context and inject event handlers.</p>
<p dir="auto">Execution flow: User controlled object keys (from API,
CMS, URL params) are spread onto element via <code
class="notranslate">{...props}</code>. The compiler generates <code
class="notranslate">spreadAttributes(props)</code> which iterates with
<code class="notranslate">Object.entries()</code> and calls <code
class="notranslate">addAttribute(value, key)</code>. The key is
interpolated as <code class="notranslate">`
${key}="${escapedValue}"`</code>. A malicious key breaks attribute
context, resulting in XSS.</p>
<h2 dir="auto">POC</h2>
<p dir="auto">Create an SSR Astro page (<code
class="notranslate">src/pages/index.astro</code>):</p>
<div class="highlight highlight-source-astro" dir="auto"><pre
class="notranslate"><span class="pl-c">---</span><span
class="pl-s1"></span>
<span class="pl-s1"><span class="pl-k"><span
class="pl-k">const</span></span> props <span class="pl-k">=</span> <span
class="pl-c1">JSON</span>.<span class="pl-c1">parse</span>(<span
class="pl-smi">Astro</span>.<span class="pl-smi">url</span>.<span
class="pl-smi">searchParams</span>.<span class="pl-c1">get</span>(<span
class="pl-s"><span class="pl-pds">'</span>props<span
class="pl-pds">'</span></span>) <span class="pl-k">||</span> <span
class="pl-s"><span class="pl-pds">'</span>{}<span
class="pl-pds">'</span></span>);</span>
<span class="pl-s1"></span><span class="pl-c">---</span>
&lt;<span class="pl-ent">html</span>&gt;
&lt;<span class="pl-ent">body</span>&gt;
&lt;<span class="pl-ent">h1</span>&gt;Hello&lt;/<span
class="pl-ent">h1</span>&gt;
&lt;<span class="pl-ent">div</span> {<span class="pl-k">...</span><span
class="pl-smi">props</span>}&gt;Move mouse here&lt;/<span
class="pl-ent">div</span>&gt;
&lt;/<span class="pl-ent">body</span>&gt;
&lt;/<span class="pl-ent">html</span>&gt;</pre></div>
<p dir="auto">Enable SSR in <code
class="notranslate">astro.config.mjs</code> (for URL based demo):</p>
<div class="highlight highlight-source-js" dir="auto"><pre
class="notranslate"><span class="pl-k">export</span> <span
class="pl-k">default</span> <span class="pl-en">defineConfig</span><span
class="pl-kos">(</span><span class="pl-kos">{</span>
  <span class="pl-c1">output</span>: <span class="pl-s">'server'</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span
class="pl-kos">;</span></pre></div>
<p dir="auto">Note: SSR is not required for the vulnerability to exist.
In static builds (default), the attack vector is compromised data
sources at build time (API, CMS, database). SSR simply makes the PoC
easier to demonstrate via URL parameters.</p>
<p dir="auto">Start the dev server and visit:</p>
<pre class="notranslate"><code
class="notranslate">http://localhost:4321/?props={"x\"
onmousemove=\"alert(document.cookie)\" y":""}
</code></pre>
<p dir="auto">URL encoded:</p>
<pre class="notranslate"><code
class="notranslate">http://localhost:4321/?props=%7B%22x%5C%22%20onmousemove%3D%5C%22alert(document.cookie)%5C%22%20y%22%3A%22%22%7D
</code></pre>
<p dir="auto">View the HTML source. The output contains:</p>
<div class="highlight highlight-text-html-basic" dir="auto"><pre
class="notranslate"><span class="pl-kos">&lt;</span><span
class="pl-ent">div</span> <span class="pl-c1">x</span>"
onmousemove="<span class="pl-s">alert(document.cookie)</span>" <span
class="pl-c1">y</span>=""<span class="pl-kos">&gt;</span>Move mouse
here<span class="pl-kos">&lt;/</span><span
class="pl-ent">div</span><span class="pl-kos">&gt;</span></pre></div>
<p dir="auto">The key <code class="notranslate">x"
onmousemove="alert(document.cookie)" y</code> breaks out of the
attribute context. Moving the mouse over the div executes the
JavaScript.</p>
<a
href="https://private-user-images.githubusercontent.com/180200014/601328447-ef69c12e-7edf-472e-97d1-3dfa540e61b4.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODE2MjU5MjYsIm5iZiI6MTc4MTYyNTYyNiwicGF0aCI6Ii8xODAyMDAwMTQvNjAxMzI4NDQ3LWVmNjljMTJlLTdlZGYtNDcyZS05N2QxLTNkZmE1NDBlNjFiNC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwNjE2JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDYxNlQxNjAwMjZaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1iZTUxZjJmNjUwYzI1ZGM5N2QxODdmYjgxM2E2YTUzMzU4ODE3Y2Q5YjQ4MTVmMmI2ZTQxNWMxYWY0ZmQ3MWExJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZwbmcifQ.-Xx9gLrWt9Z92y_X_NO1dRminGIoHc4ky1_2Fud-ssM"><img
width="1919" height="992" alt="Captura de tela 2026-06-02 005906"
src="https://private-user-images.githubusercontent.com/180200014/601328447-ef69c12e-7edf-472e-97d1-3dfa540e61b4.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODE2MjU5MjYsIm5iZiI6MTc4MTYyNTYyNiwicGF0aCI6Ii8xODAyMDAwMTQvNjAxMzI4NDQ3LWVmNjljMTJlLTdlZGYtNDcyZS05N2QxLTNkZmE1NDBlNjFiNC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwNjE2JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDYxNlQxNjAwMjZaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1iZTUxZjJmNjUwYzI1ZGM5N2QxODdmYjgxM2E2YTUzMzU4ODE3Y2Q5YjQ4MTVmMmI2ZTQxNWMxYWY0ZmQ3MWExJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZwbmcifQ.-Xx9gLrWt9Z92y_X_NO1dRminGIoHc4ky1_2Fud-ssM"
style="max-width: 100%; height: auto; max-height: 992px;; aspect-ratio:
1919 / 992; background-color: var(--bgColor-muted); border-radius: 6px"
class="js-gh-image-fallback"></a>
<h2 dir="auto">Impact</h2>
<p dir="auto">An attacker can execute arbitrary JavaScript in the
context of a victim's browser session on any Astro application that
spreads object props from untrusted sources onto HTML elements. This is
a common pattern when integrating with external APIs or CMS systems.
Exploitation enables session hijacking via cookie theft, credential
theft by injecting fake login forms or keyloggers, defacement of the
rendered page, and redirection to attacker controlled domains.</p>
<p dir="auto">The vulnerability affects all Astro versions that support
spread syntax on HTML elements and is exploitable in SSR, SSG (if build
time data is compromised), and hybrid deployments.</p></blockquote>
<h4><a
href="https://bounce.depfu.com/github.com/withastro/astro/security/advisories/GHSA-xr5h-phrj-8vxv">🚨
Astro: Server island encrypted parameters vulnerable to cross-component
replay</a></h4>
<blockquote><h3 dir="auto">Impact</h3>
<p dir="auto">Astro versions prior to 6.1.10 used AES-GCM encryption to
protect the confidentiality and integrity of server island props and
slots parameters, but did not bind the ciphertext to its intended
component or parameter type. An attacker could replay one component's
encrypted props (<code class="notranslate">p</code>) value as another
component's slots (<code class="notranslate">s</code>) value, or vice
versa.</p>
<p dir="auto">Since slots contain raw unescaped HTML while props may
contain user-controlled values, this could lead to XSS in applications
that meet <strong>all</strong> of the following conditions:</p>
<ul dir="auto">
<li>The application uses server islands</li>
<li>Two different server island components share the same key name for a
prop and a slot</li>
<li>An attacker has full control over the value of the overlapping prop
(requires a dynamically rendered page)</li>
</ul>
<p dir="auto">These conditions are very unlikely to occur in real-world
production applications.</p>
<h3 dir="auto">Patches</h3>
<p dir="auto">This has been patched in
<strong>astro@6.1.10</strong>.</p>
<p dir="auto">The fix binds each encrypted parameter to its target
component and purpose using AES-GCM authenticated additional data (AAD).
Each ciphertext now includes context like <code
class="notranslate">props:IslandName</code> or <code
class="notranslate">slots:IslandName</code>, so encrypted data for one
component cannot be replayed against a different component, and
encrypted props cannot be reused as slots.</p>
<h3 dir="auto">References</h3>
<ul dir="auto">
<li>Fix PR: <a
href="https://bounce.depfu.com/github.com/withastro/astro/pull/16457">#16457</a>
</li>
<li>Example demonstrating the vulnerability: <a
href="https://bounce.depfu.com/github.com/CyberSecurityAustria/ACSC2026-web-astronomical">https://github.com/CyberSecurityAustria/ACSC2026-web-astronomical</a>
</li>
</ul></blockquote>
<h4><a
href="https://bounce.depfu.com/github.com/withastro/astro/security/advisories/GHSA-j687-52p2-xcff">🚨
Astro: XSS in define:vars via incomplete </script> tag
sanitization</a></h4>
<blockquote><h2 dir="auto">Summary</h2>
<p dir="auto">The <code class="notranslate">defineScriptVars</code>
function in Astro's server-side rendering pipeline uses a case-sensitive
regex <code class="notranslate">/&lt;\/script&gt;/g</code> to sanitize
values injected into inline <code
class="notranslate">&lt;script&gt;</code> tags via the <code
class="notranslate">define:vars</code> directive. HTML parsers close
<code class="notranslate">&lt;script&gt;</code> elements
case-insensitively and also accept whitespace or <code
class="notranslate">/</code> before the closing <code
class="notranslate">&gt;</code>, allowing an attacker to bypass the
sanitization with payloads like <code
class="notranslate">&lt;/Script&gt;</code>, <code
class="notranslate">&lt;/script &gt;</code>, or <code
class="notranslate">&lt;/script/&gt;</code> and inject arbitrary
HTML/JavaScript.</p>
<h2 dir="auto">Details</h2>
<p dir="auto">The vulnerable function is <code
class="notranslate">defineScriptVars</code> at <code
class="notranslate">packages/astro/src/runtime/server/render/util.ts:42-53</code>:</p>
<div class="highlight highlight-source-ts" dir="auto"><pre
class="notranslate"><span class="pl-k">export</span> <span
class="pl-k">function</span> <span
class="pl-en">defineScriptVars</span><span class="pl-kos">(</span><span
class="pl-s1">vars</span>: <span class="pl-smi">Record</span><span
class="pl-c1">&lt;</span><span class="pl-smi">any</span><span
class="pl-kos">,</span> <span class="pl-smi">any</span><span
class="pl-c1">&gt;</span><span class="pl-kos">)</span> <span
class="pl-kos">{</span>
<span class="pl-k">let</span> <span class="pl-s1">output</span> <span
class="pl-c1">=</span> <span class="pl-s">''</span><span
class="pl-kos">;</span>
<span class="pl-k">for</span> <span class="pl-kos">(</span><span
class="pl-k">const</span> <span class="pl-kos">[</span><span
class="pl-s1">key</span><span class="pl-kos">,</span> <span
class="pl-s1">value</span><span class="pl-kos">]</span> <span
class="pl-k">of</span> <span class="pl-v">Object</span><span
class="pl-kos">.</span><span class="pl-en">entries</span><span
class="pl-kos">(</span><span class="pl-s1">vars</span><span
class="pl-kos">)</span><span class="pl-kos">)</span> <span
class="pl-kos">{</span>
<span class="pl-s1">output</span> <span class="pl-c1">+=</span> <span
class="pl-s">`const <span class="pl-s1"><span
class="pl-kos">${</span><span class="pl-en">toIdent</span><span
class="pl-kos">(</span><span class="pl-s1">key</span><span
class="pl-kos">)</span><span class="pl-kos">}</span></span> = <span
class="pl-s1"><span class="pl-kos">${</span><span
class="pl-c1">JSON</span><span class="pl-kos">.</span><span
class="pl-en">stringify</span><span class="pl-kos">(</span><span
class="pl-s1">value</span><span class="pl-kos">)</span><span
class="pl-kos">?.</span><span class="pl-en">replace</span><span
class="pl-kos">(</span></span></span>
<span class="pl-s"><span class="pl-s1"> <span class="pl-pds"><span
class="pl-c1">/</span><span class="pl-s">&lt;</span><span
class="pl-cce">\/</span><span class="pl-s">s</span><span
class="pl-s">c</span><span class="pl-s">r</span><span
class="pl-s">i</span><span class="pl-s">p</span><span
class="pl-s">t</span><span class="pl-s">&gt;</span><span
class="pl-c1">/</span>g</span><span class="pl-kos">,</span> <span
class="pl-c">// ← Case-sensitive, exact match only</span></span></span>
<span class="pl-s"><span class="pl-s1"> <span
class="pl-s">'\\x3C/script&gt;'</span><span
class="pl-kos">,</span></span></span>
<span class="pl-s"><span class="pl-s1"> <span
class="pl-kos">)</span><span
class="pl-kos">}</span></span>;\n`</span><span class="pl-kos">;</span>
	<span class="pl-kos">}</span>
<span class="pl-k">return</span> <span
class="pl-en">markHTMLString</span><span class="pl-kos">(</span><span
class="pl-s1">output</span><span class="pl-kos">)</span><span
class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">This function is called from <code
class="notranslate">renderElement</code> at <code
class="notranslate">util.ts:172-174</code> when a <code
class="notranslate">&lt;script&gt;</code> element has <code
class="notranslate">define:vars</code>:</p>
<div class="highlight highlight-source-ts" dir="auto"><pre
class="notranslate"><span class="pl-k">if</span> <span
class="pl-kos">(</span><span class="pl-s1">name</span> <span
class="pl-c1">===</span> <span class="pl-s">'script'</span><span
class="pl-kos">)</span> <span class="pl-kos">{</span>
<span class="pl-k">delete</span> <span class="pl-s1">props</span><span
class="pl-kos">.</span><span class="pl-c1">hoist</span><span
class="pl-kos">;</span>
<span class="pl-s1">children</span> <span class="pl-c1">=</span> <span
class="pl-en">defineScriptVars</span><span class="pl-kos">(</span><span
class="pl-s1">defineVars</span><span class="pl-kos">)</span> <span
class="pl-c1">+</span> <span class="pl-s">'\n'</span> <span
class="pl-c1">+</span> <span class="pl-s1">children</span><span
class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">The regex <code
class="notranslate">/&lt;\/script&gt;/g</code> fails to match three
classes of closing script tags that HTML parsers accept per the <a
href="https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody">HTML
specification §13.2.6.4</a>:</p>
<ol dir="auto">
<li>
<strong>Case variations</strong>: <code
class="notranslate">&lt;/Script&gt;</code>, <code
class="notranslate">&lt;/SCRIPT&gt;</code>, <code
class="notranslate">&lt;/sCrIpT&gt;</code> — HTML tag names are
case-insensitive but the regex has no <code class="notranslate">i</code>
flag.</li>
<li>
<strong>Whitespace before <code
class="notranslate">&gt;</code></strong>: <code
class="notranslate">&lt;/script &gt;</code>, <code
class="notranslate">&lt;/script\t&gt;</code>, <code
class="notranslate">&lt;/script\n&gt;</code> — after the tag name, the
HTML tokenizer enters the "before attribute name" state on ASCII
whitespace.</li>
<li>
<strong>Self-closing slash</strong>: <code
class="notranslate">&lt;/script/&gt;</code> — the tokenizer enters
"self-closing start tag" state on <code
class="notranslate">/</code>.</li>
</ol>
<p dir="auto"><code class="notranslate">JSON.stringify()</code> does not
escape <code class="notranslate">&lt;</code>, <code
class="notranslate">&gt;</code>, or <code class="notranslate">/</code>
characters, so all these payloads pass through serialization
unchanged.</p>
<p dir="auto"><strong>Execution flow:</strong> User-controlled input
(e.g., <code class="notranslate">Astro.url.searchParams</code>) →
assigned to a variable → passed via <code
class="notranslate">define:vars</code> on a <code
class="notranslate">&lt;script&gt;</code> tag → <code
class="notranslate">renderElement</code> → <code
class="notranslate">defineScriptVars</code> → incomplete sanitization →
injected into <code class="notranslate">&lt;script&gt;</code> block in
HTML response → browser closes the script element early →
attacker-controlled HTML parsed and executed.</p>
<h2 dir="auto">PoC</h2>
<p dir="auto"><strong>Step 1:</strong> Create an SSR Astro page (<code
class="notranslate">src/pages/index.astro</code>):</p>
<div class="highlight highlight-source-astro" dir="auto"><pre
class="notranslate"><span class="pl-c">---</span><span
class="pl-s1"></span>
<span class="pl-s1"><span class="pl-k"><span
class="pl-k">const</span></span> name <span class="pl-k">=</span> <span
class="pl-smi">Astro</span>.<span class="pl-smi">url</span>.<span
class="pl-smi">searchParams</span>.<span class="pl-c1">get</span>(<span
class="pl-s"><span class="pl-pds">'</span>name<span
class="pl-pds">'</span></span>) <span class="pl-k">||</span> <span
class="pl-s"><span class="pl-pds">'</span>World<span
class="pl-pds">'</span></span>;</span>
<span class="pl-s1"></span><span class="pl-c">---</span>
&lt;<span class="pl-ent">html</span>&gt;
&lt;<span class="pl-ent">body</span>&gt;
&lt;<span class="pl-ent">h1</span>&gt;Hello&lt;/<span
class="pl-ent">h1</span>&gt;
&lt;<span class="pl-ent">script</span> <span
class="pl-e">define:vars</span>=<span class="pl-pse">{</span>{ <span
class="pl-smi">name</span> }<span class="pl-pse">}</span>&gt;
    console.log(name);
  &lt;/<span class="pl-ent">script</span>&gt;
&lt;/<span class="pl-ent">body</span>&gt;
&lt;/<span class="pl-ent">html</span>&gt;</pre></div>
<p dir="auto"><strong>Step 2:</strong> Ensure SSR is enabled in <code
class="notranslate">astro.config.mjs</code>:</p>
<div class="highlight highlight-source-js" dir="auto"><pre
class="notranslate"><span class="pl-k">export</span> <span
class="pl-k">default</span> <span class="pl-en">defineConfig</span><span
class="pl-kos">(</span><span class="pl-kos">{</span>
  <span class="pl-c1">output</span>: <span class="pl-s">'server'</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span
class="pl-kos">;</span></pre></div>
<p dir="auto"><strong>Step 3:</strong> Start the dev server and
visit:</p>
<pre class="notranslate"><code
class="notranslate">http://localhost:4321/?name=&lt;/Script&gt;&lt;img/src=x%20onerror=alert(document.cookie)&gt;
</code></pre>
<p dir="auto"><strong>Step 4:</strong> View the HTML source. The output
contains:</p>
<div class="highlight highlight-text-html-basic" dir="auto"><pre
class="notranslate"><span class="pl-kos">&lt;</span><span
class="pl-ent">script</span><span class="pl-kos">&gt;</span><span
class="pl-k">const</span> <span class="pl-s1">name</span> <span
class="pl-c1">=</span> "<span class="pl-kos">&lt;/</span><span
class="pl-ent">Script</span><span class="pl-kos">&gt;</span><span
class="pl-kos">&lt;</span><span class="pl-ent">img</span>/src=x
onerror=alert(document.cookie)<span class="pl-kos">&gt;</span>";
  console.log(name);
<span class="pl-kos">&lt;/</span><span class="pl-ent">script</span><span
class="pl-kos">&gt;</span></pre></div>
<p dir="auto">The browser's HTML parser matches <code
class="notranslate">&lt;/Script&gt;</code> case-insensitively, closing
the script block. The <code class="notranslate">&lt;img
onerror=alert(document.cookie)&gt;</code> is then parsed as HTML and the
JavaScript in <code class="notranslate">onerror</code> executes.</p>
<p dir="auto"><strong>Alternative bypass payloads:</strong></p>
<pre class="notranslate"><code class="notranslate">/?name=&lt;/script
&gt;&lt;img/src=x onerror=alert(1)&gt;
/?name=&lt;/script/&gt;&lt;img/src=x onerror=alert(1)&gt;
/?name=&lt;/SCRIPT&gt;&lt;img/src=x onerror=alert(1)&gt;
</code></pre>
<h2 dir="auto">Impact</h2>
<p dir="auto">An attacker can execute arbitrary JavaScript in the
context of a victim's browser session on any SSR Astro application that
passes request-derived data to <code
class="notranslate">define:vars</code> on a <code
class="notranslate">&lt;script&gt;</code> tag. This is a documented and
expected usage pattern in Astro.</p>
<p dir="auto">Exploitation enables:</p>
<ul dir="auto">
<li>
<strong>Session hijacking</strong> via cookie theft (<code
class="notranslate">document.cookie</code>)</li>
<li>
<strong>Credential theft</strong> by injecting fake login forms or
keyloggers</li>
<li>
<strong>Defacement</strong> of the rendered page</li>
<li>
<strong>Redirection</strong> to attacker-controlled domains</li>
</ul>
<p dir="auto">The vulnerability affects all Astro versions that support
<code class="notranslate">define:vars</code> and is exploitable in any
SSR deployment where user input reaches a <code
class="notranslate">define:vars</code> script variable.</p>
<h2 dir="auto">Recommended Fix</h2>
<p dir="auto">Replace the case-sensitive exact-match regex with a
comprehensive escape that covers all HTML parser edge cases. The
simplest correct fix is to escape all <code
class="notranslate">&lt;</code> characters in the JSON output:</p>
<div class="highlight highlight-source-ts" dir="auto"><pre
class="notranslate"><span class="pl-k">export</span> <span
class="pl-k">function</span> <span
class="pl-en">defineScriptVars</span><span class="pl-kos">(</span><span
class="pl-s1">vars</span>: <span class="pl-smi">Record</span><span
class="pl-c1">&lt;</span><span class="pl-smi">any</span><span
class="pl-kos">,</span> <span class="pl-smi">any</span><span
class="pl-c1">&gt;</span><span class="pl-kos">)</span> <span
class="pl-kos">{</span>
<span class="pl-k">let</span> <span class="pl-s1">output</span> <span
class="pl-c1">=</span> <span class="pl-s">''</span><span
class="pl-kos">;</span>
<span class="pl-k">for</span> <span class="pl-kos">(</span><span
class="pl-k">const</span> <span class="pl-kos">[</span><span
class="pl-s1">key</span><span class="pl-kos">,</span> <span
class="pl-s1">value</span><span class="pl-kos">]</span> <span
class="pl-k">of</span> <span class="pl-v">Object</span><span
class="pl-kos">.</span><span class="pl-en">entries</span><span
class="pl-kos">(</span><span class="pl-s1">vars</span><span
class="pl-kos">)</span><span class="pl-kos">)</span> <span
class="pl-kos">{</span>
<span class="pl-s1">output</span> <span class="pl-c1">+=</span> <span
class="pl-s">`const <span class="pl-s1"><span
class="pl-kos">${</span><span class="pl-en">toIdent</span><span
class="pl-kos">(</span><span class="pl-s1">key</span><span
class="pl-kos">)</span><span class="pl-kos">}</span></span> = <span
class="pl-s1"><span class="pl-kos">${</span><span
class="pl-c1">JSON</span><span class="pl-kos">.</span><span
class="pl-en">stringify</span><span class="pl-kos">(</span><span
class="pl-s1">value</span><span class="pl-kos">)</span><span
class="pl-kos">?.</span><span class="pl-en">replace</span><span
class="pl-kos">(</span></span></span>
<span class="pl-s"><span class="pl-s1"> <span class="pl-pds"><span
class="pl-c1">/</span><span class="pl-s">&lt;</span><span
class="pl-c1">/</span>g</span><span
class="pl-kos">,</span></span></span>
<span class="pl-s"><span class="pl-s1"> <span
class="pl-s">'\\u003c'</span><span class="pl-kos">,</span></span></span>
<span class="pl-s"><span class="pl-s1"> <span
class="pl-kos">)</span><span
class="pl-kos">}</span></span>;\n`</span><span class="pl-kos">;</span>
	<span class="pl-kos">}</span>
<span class="pl-k">return</span> <span
class="pl-en">markHTMLString</span><span class="pl-kos">(</span><span
class="pl-s1">output</span><span class="pl-kos">)</span><span
class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">This is the standard approach used by frameworks like
Next.js and Rails. Replacing every <code class="notranslate">&lt;</code>
with <code class="notranslate">\u003c</code> is safe inside JSON string
contexts (JavaScript treats <code class="notranslate">\u003c</code> as
<code class="notranslate">&lt;</code> at runtime) and eliminates all
possible <code class="notranslate">&lt;/script&gt;</code> variants
including case variations, whitespace, and self-closing
forms.</p></blockquote>
</details>

<details>
<summary>Release Notes</summary>
<p><em>Too many releases to show here. View the <a
href="https://github.com/withastro/astro/blob/main/packages/astro/CHANGELOG.md">full
release notes</a>.</em></p>
</details>





#### ↗️ @​astrojs/markdown-remark (_indirect_, 6.3.11 → 7.2.0) ·
[Repo](https://github.com/withastro/astro)





Sorry, we couldn't find anything useful about this release.



#### ↗️ @​astrojs/prism (_indirect_, 3.3.0 → 4.0.2) ·
[Repo](https://github.com/withastro/astro)





Sorry, we couldn't find anything useful about this release.



#### ↗️ @​astrojs/telemetry (_indirect_, 3.3.0 → 3.3.2) ·
[Repo](https://github.com/withastro/astro) ·
[Changelog](https://github.com/withastro/astro/blob/main/packages/telemetry/CHANGELOG.md)



<details>
<summary>Release Notes</summary>

<h4>3.3.2 (from changelog)</h4>
<blockquote><em>More info than we can show here.</em></blockquote>

<h4>3.3.1 (from changelog)</h4>
<blockquote><em>More info than we can show here.</em></blockquote>
<p><em>Does any of this look wrong? <a
href="https://depfu.com/packages/npm/@astrojs%2Ftelemetry/feedback">Please
let us know.</a></em></p>
</details>





#### ↗️ @​shikijs/core (_indirect_, 3.23.0 → 4.2.0) ·
[Repo](https://github.com/shikijs/shiki)



<details>
<summary>Release Notes</summary>
<h4><a
href="https://github.com/shikijs/shiki/releases/tag/v4.2.0">4.2.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<p><em>Does any of this look wrong? <a
href="https://depfu.com/packages/npm/@shikijs%2Fcore/feedback">Please
let us know.</a></em></p>
</details>

<details>
<summary>Commits</summary>
<p><a
href="https://github.com/shikijs/shiki/compare/2b33c0cdcedf3e00f65cac7228c62f7f1bcbf86a...1d56dae84801bad3a48dc7104437fbc21819ee4c">See
the full diff on Github</a>. The new version differs by more commits
than we can show here.</p>
</details>




#### ↗️ @​shikijs/langs (_indirect_, 3.23.0 → 4.2.0) ·
[Repo](https://github.com/shikijs/shiki)



<details>
<summary>Release Notes</summary>
<h4><a
href="https://github.com/shikijs/shiki/releases/tag/v4.2.0">4.2.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<p><em>Does any of this look wrong? <a
href="https://depfu.com/packages/npm/@shikijs%2Flangs/feedback">Please
let us know.</a></em></p>
</details>

<details>
<summary>Commits</summary>
<p><a
href="https://github.com/shikijs/shiki/compare/2b33c0cdcedf3e00f65cac7228c62f7f1bcbf86a...1d56dae84801bad3a48dc7104437fbc21819ee4c">See
the full diff on Github</a>. The new version differs by more commits
than we can show here.</p>
</details>




#### ↗️ @​shikijs/themes (_indirect_, 3.23.0 → 4.2.0) ·
[Repo](https://github.com/shikijs/shiki)



<details>
<summary>Release Notes</summary>
<h4><a
href="https://github.com/shikijs/shiki/releases/tag/v4.2.0">4.2.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<p><em>Does any of this look wrong? <a
href="https://depfu.com/packages/npm/@shikijs%2Fthemes/feedback">Please
let us know.</a></em></p>
</details>

<details>
<summary>Commits</summary>
<p><a
href="https://github.com/shikijs/shiki/compare/2b33c0cdcedf3e00f65cac7228c62f7f1bcbf86a...1d56dae84801bad3a48dc7104437fbc21819ee4c">See
the full diff on Github</a>. The new version differs by more commits
than we can show here.</p>
</details>




#### ↗️ p-limit (_indirect_, 6.2.0 → 7.3.0) ·
[Repo](https://github.com/sindresorhus/p-limit)



<details>
<summary>Release Notes</summary>
<h4><a
href="https://github.com/sindresorhus/p-limit/releases/tag/v7.3.0">7.3.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/sindresorhus/p-limit/releases/tag/v7.2.0">7.2.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/sindresorhus/p-limit/releases/tag/v7.1.1">7.1.1</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/sindresorhus/p-limit/releases/tag/v7.1.0">7.1.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/sindresorhus/p-limit/releases/tag/v7.0.0">7.0.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<p><em>Does any of this look wrong? <a
href="https://depfu.com/packages/npm/p-limit/feedback">Please let us
know.</a></em></p>
</details>

<details>
<summary>Commits</summary>
<p><a
href="https://github.com/sindresorhus/p-limit/compare/7d14b3f04aa990f621a853e24e2a4b796baf1ec9...886bda51d7cd38b5fe48e7e4516b5b1ce6f145ba">See
the full diff on Github</a>. The new version differs by more commits
than we can show here.</p>
</details>




#### ↗️ p-queue (_indirect_, 8.1.1 → 9.3.0) ·
[Repo](https://github.com/sindresorhus/p-queue)



<details>
<summary>Release Notes</summary>
<h4><a
href="https://github.com/sindresorhus/p-queue/releases/tag/v9.3.0">9.3.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/sindresorhus/p-queue/releases/tag/v9.2.0">9.2.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/sindresorhus/p-queue/releases/tag/v9.1.2">9.1.2</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/sindresorhus/p-queue/releases/tag/v9.1.1">9.1.1</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/sindresorhus/p-queue/releases/tag/v9.1.0">9.1.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/sindresorhus/p-queue/releases/tag/v9.0.1">9.0.1</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/sindresorhus/p-queue/releases/tag/v9.0.0">9.0.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<p><em>Does any of this look wrong? <a
href="https://depfu.com/packages/npm/p-queue/feedback">Please let us
know.</a></em></p>
</details>

<details>
<summary>Commits</summary>
<p><a
href="https://github.com/sindresorhus/p-queue/compare/26b09b90a58ea1b8006ef5f35abbbae518d8ee18...cfa917af261fb6db9eb1281221ba21093eb49e3d">See
the full diff on Github</a>. The new version differs by more commits
than we can show here.</p>
</details>




#### ↗️ p-timeout (_indirect_, 6.1.4 → 7.0.1) ·
[Repo](https://github.com/sindresorhus/p-timeout)



<details>
<summary>Release Notes</summary>
<h4><a
href="https://github.com/sindresorhus/p-timeout/releases/tag/v7.0.1">7.0.1</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/sindresorhus/p-timeout/releases/tag/v7.0.0">7.0.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<p><em>Does any of this look wrong? <a
href="https://depfu.com/packages/npm/p-timeout/feedback">Please let us
know.</a></em></p>
</details>

<details>
<summary>Commits</summary>
<p><a
href="https://github.com/sindresorhus/p-timeout/compare/16b290ed4eed35f977537756411261f476623586...245066ef7daa5e74024d5b6a188ae599a1b7bfdf">See
the full diff on Github</a>. The new version differs by more commits
than we can show here.</p>
</details>




#### ↗️ shiki (_indirect_, 3.23.0 → 4.2.0) ·
[Repo](https://github.com/shikijs/shiki) ·
[Changelog](https://github.com/shikijs/shiki/blob/main/CHANGELOG.md)



<details>
<summary>Release Notes</summary>
<h4><a
href="https://github.com/shikijs/shiki/releases/tag/v4.2.0">4.2.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/shikijs/shiki/releases/tag/v4.1.0">4.1.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/shikijs/shiki/releases/tag/v4.0.2">4.0.2</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/shikijs/shiki/releases/tag/v4.0.1">4.0.1</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<h4><a
href="https://github.com/shikijs/shiki/releases/tag/v4.0.0">4.0.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<p><em>Does any of this look wrong? <a
href="https://depfu.com/packages/npm/shiki/feedback">Please let us
know.</a></em></p>
</details>

<details>
<summary>Commits</summary>
<p><a
href="https://github.com/shikijs/shiki/compare/2b33c0cdcedf3e00f65cac7228c62f7f1bcbf86a...1d56dae84801bad3a48dc7104437fbc21819ee4c">See
the full diff on Github</a>. The new version differs by more commits
than we can show here.</p>
</details>




#### ↗️ smol-toml (_indirect_, 1.6.1 → 1.7.0) ·
[Repo](https://github.com/squirrelchat/smol-toml)



<details>
<summary>Release Notes</summary>
<h4><a
href="https://github.com/squirrelchat/smol-toml/releases/tag/v1.7.0">1.7.0</a></h4>

<blockquote><em>More info than we can show here.</em></blockquote>
<p><em>Does any of this look wrong? <a
href="https://depfu.com/packages/npm/smol-toml/feedback">Please let us
know.</a></em></p>
</details>

<details>
<summary>Commits</summary>
<p><a
href="https://github.com/squirrelchat/smol-toml/compare/072b64fd0094b1d7d3bb1a124d282828069a7aa0...a62f06faf4e45ab0a581def86c116f9706edc9df">See
the full diff on Github</a>. The new version differs by more commits
than we can show here.</p>
</details>




#### 🆕 @​clack/core (_added_, 1.4.2)
#### 🆕 @​clack/prompts (_added_, 1.6.0)
#### 🆕 @​shikijs/primitive (_added_, 4.2.0)
#### 🆕 get-tsconfig (_added_, 5.0.0-beta.4)
#### 🆕 resolve-pkg-maps (_added_, 1.0.0)
#### 🆕 tinyclip (_added_, 0.1.15)
#### 🆕 @​astrojs/compiler (_added_, 4.0.0)
#### 🆕 @​astrojs/internal-helpers (_added_, 0.10.0)
#### 🆕 is-docker (_added_, 4.0.0)
#### 🆕 vite (_added_, 7.3.5)
#### 🗑️ ansi-align (_removed_)
#### 🗑️ tsconfck (_removed_)
#### 🗑️ zod-to-ts (_removed_)
#### 🗑️ base-64 (_removed_)
#### 🗑️ boxen (_removed_)
#### 🗑️ cli-boxes (_removed_)
#### 🗑️ deterministic-object-hash (_removed_)
#### 🗑️ import-meta-resolve (_removed_)
#### 🗑️ yocto-spinner (_removed_)
#### 🗑️ zod-to-json-schema (_removed_)
#### 🗑️ typescript (_removed_)
#### 🗑️ type-fest (_removed_)
#### 🗑️ widest-line (_removed_)
#### 🗑️ camelcase (_removed_)
#### 🗑️ common-ancestor-path (_removed_)
#### 🗑️ es-module-lexer (_removed_)








---
![Depfu
Status](https://depfu.com/badges/6b62d1fc8d2dc3ff015ad9ad8f69c568/stats.svg)

[Depfu](https://depfu.com) will automatically keep this PR
conflict-free, as long as you don't add any commits to this branch
yourself. You can also trigger a rebase manually by commenting with
`@depfu rebase`.

<details><summary>All Depfu comment commands</summary>
<blockquote><dl>
<dt>@​depfu rebase</dt><dd>Rebases against your default branch and
redoes this update</dd>
<dt>@​depfu recreate</dt><dd>Recreates this PR, overwriting any edits
that you've made to it</dd>
<dt>@​depfu merge</dt><dd>Merges this PR once your tests are passing and
conflicts are resolved</dd>
<dt>@​depfu cancel merge</dt><dd>Cancels automatic merging of this
PR</dd>
<dt>@​depfu close</dt><dd>Closes this PR and deletes the branch</dd>
<dt>@​depfu reopen</dt><dd>Restores the branch and reopens this PR (if
it's closed)</dd>
<dt>@​depfu pause</dt><dd>Ignores all future updates for this dependency
and closes this PR</dd>
<dt>@​depfu pause [minor|major]</dt><dd>Ignores all future minor/major
updates for this dependency and closes this PR</dd>
<dt>@​depfu resume</dt><dd>Future versions of this dependency will
create PRs again (leaves this PR as is)</dd>
</dl></blockquote>
</details>

---------

Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: milailijevic <mila.ilijevic@gmail.com>
@depfu

depfu Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

Closing because this update has already been applied

@depfu depfu Bot closed this Jul 28, 2026
@depfu
depfu Bot deleted the depfu/update/npm/@astrojs/cloudflare-13.7.0 branch July 28, 2026 09:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant