Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to Instatic will be documented here.

This project is pre-1.0. Breaking changes may appear in minor or patch releases until a stable release line exists.

## 0.0.19 - 2026-09-10

### Security

- Closed a server-side request forgery in the media storage write path ([GHSA-9pq7-m5wf-r7f6](https://github.com/CoreBunch/Instatic/security/advisories/GHSA-9pq7-m5wf-r7f6)). A plugin holding only `media.storage.adapter` supplies the step URLs in an upload plan, and the executor streamed the bytes to them with an unguarded `fetch()`, so the grant carried the network reach of `network.outbound` without asking for it: arbitrary `PUT` and `POST` at loopback, private, link-local, and cloud-metadata addresses, with plugin-chosen headers and the validated media bytes as the body. This is the write-side sibling of the media migration SSRF fixed in 0.0.18, which closed the read path and left this one open. Upload plan steps now go through the same SSRF-safe guard as the read path: internal addresses are refused before a connection opens, the connection is pinned to the checked IP, and every redirect hop is re-validated. Reported by [@skeletonsec](https://github.com/skeletonsec).

### Publishing and runtime

- Fixed the runtime dependency package server returning 404 for every package asset on Windows hosts ([GHSA-hwp9-vc7h-gvvf](https://github.com/CoreBunch/Instatic/security/advisories/GHSA-hwp9-vc7h-gvvf)). The containment check that keeps a resolved path inside the cache directory compared against a hard-coded forward slash, but `path.resolve` produces backslashes on Windows, so the check was false for every legitimate path and the endpoint refused all runtime package assets. It fails closed, so nothing was exposed. Containment is now decided with `path.relative()`, which is correct on both separators, and the same helper replaced a prefix comparison in the site-script workspace that carried no separator at all and would have accepted a sibling directory whose name merely began with the root. Reported by [@uziii2208](https://github.com/uziii2208).

## 0.0.18 - 2026-09-01

### Security
Expand Down
2 changes: 1 addition & 1 deletion docs/deployment/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ INSTATIC_IMAGE=ghcr.io/corebunch/instatic:latest docker compose -f compose.prod.
Pin a semver tag for predictable upgrades:

```sh
INSTATIC_IMAGE=ghcr.io/corebunch/instatic:0.0.18 docker compose -f compose.prod.yml -f compose.sqlite.yml up -d
INSTATIC_IMAGE=ghcr.io/corebunch/instatic:0.0.19 docker compose -f compose.prod.yml -f compose.sqlite.yml up -d
```

Source builds remain supported for contributors and release-candidate testing:
Expand Down
8 changes: 4 additions & 4 deletions docs/deployment/docker-image.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ GHCR is the canonical image registry:

```sh
docker pull ghcr.io/corebunch/instatic:latest
docker pull ghcr.io/corebunch/instatic:0.0.18
docker pull ghcr.io/corebunch/instatic:0.0.19
```

The v0.0.18 published image is built for `linux/amd64`. Use it on Railway and x86_64 VPS/container hosts. ARM64 hosts should build from source for now, or wait for the native arm64 release job before pulling GHCR images directly.
The v0.0.19 published image is built for `linux/amd64`. Use it on Railway and x86_64 VPS/container hosts. ARM64 hosts should build from source for now, or wait for the native arm64 release job before pulling GHCR images directly.

## Run With SQLite

Expand Down Expand Up @@ -92,7 +92,7 @@ Replace `instatic:local` with `ghcr.io/corebunch/instatic:<tag>` when deploying
Create an app service from Docker image source:

```txt
ghcr.io/corebunch/instatic:0.0.18
ghcr.io/corebunch/instatic:0.0.19
```

Attach a Railway volume at `/app/storage`, set the health check path to `/health`, and set app variables:
Expand All @@ -109,7 +109,7 @@ RAILWAY_RUN_UID=0

`RAILWAY_RUN_UID=0` is required because Railway volumes are mounted as `root` and the published image otherwise runs as the non-root `bun` user. `PUBLIC_ORIGIN=https://${{RAILWAY_PUBLIC_DOMAIN}}` gives Instatic the public origin for its CSRF check now that Railway terminates HTTPS at the edge; the server would auto-detect the same value from `RAILWAY_PUBLIC_DOMAIN`, but setting it explicitly survives custom-domain edits.

Enable Railway Image Auto Updates when you want Railway to move the service forward automatically during a maintenance window. Use `:latest` for "always follow the newest image", or a semver tag such as `:0.0.18` if you want Railway's semver update controls.
Enable Railway Image Auto Updates when you want Railway to move the service forward automatically during a maintenance window. Use `:latest` for "always follow the newest image", or a semver tag such as `:0.0.19` if you want Railway's semver update controls.

## Run On Render From The Image

Expand Down
8 changes: 4 additions & 4 deletions docs/deployment/railway.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Railway is the simplest managed target for Instatic because it can run the publi
Both templates use:

```txt
Image=ghcr.io/corebunch/instatic:0.0.18
Image=ghcr.io/corebunch/instatic:0.0.19
PORT=8080
UPLOADS_DIR=/app/storage/uploads
STATIC_DIR=/app/dist
Expand All @@ -32,7 +32,7 @@ Configure the app service health check path as `/health`. If Railway asks which
Use a Docker image source for production installs:

```txt
ghcr.io/corebunch/instatic:0.0.18
ghcr.io/corebunch/instatic:0.0.19
```

The image already runs:
Expand All @@ -48,7 +48,7 @@ Recommended service settings:
| Setting | Value |
|---|---|
| Source | Docker image |
| Image | `ghcr.io/corebunch/instatic:0.0.18` |
| Image | `ghcr.io/corebunch/instatic:0.0.19` |
| Public networking | HTTP enabled |
| Target port | `8080` |
| Healthcheck path | `/health` |
Expand Down Expand Up @@ -135,7 +135,7 @@ Railway volume backups apply to mounted volumes. For Postgres, use Railway's dat
Enable Railway Image Auto Updates on the app service:

- Use `ghcr.io/corebunch/instatic:latest` when you want the service to redeploy whenever the `latest` tag moves.
- Use a semver tag like `ghcr.io/corebunch/instatic:0.0.18` when you want Railway to stage matching patch or minor updates according to the service's auto-update preference.
- Use a semver tag like `ghcr.io/corebunch/instatic:0.0.19` when you want Railway to stage matching patch or minor updates according to the service's auto-update preference.

Set a maintenance window before enabling automatic updates on sites with attached volumes.

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "instatic",
"private": true,
"version": "0.0.18",
"version": "0.0.19",
"engines": {
"bun": ">=1.3.0 <1.4.0"
},
Expand Down
Loading