Skip to content
Open
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
25 changes: 0 additions & 25 deletions .changeset/security-hardening-pass.md

This file was deleted.

26 changes: 26 additions & 0 deletions packages/passmint/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
# passmint

## 0.2.0

### Minor Changes

- a48448f: Security hardening pass — 28 new tests, 0 regressions.

**New guarantees (some of these tighten existing inputs):**

- **`ZipAssembler.add()`** now rejects `..` path segments, backslashes, drive-letter prefixes (e.g. `C:\`), and NUL bytes. Prevents ZIP-Slip-class issues for downstream consumers who use `ZipAssembler` directly with untrusted filenames. The internal `.pkpass` pipeline was already safe; this hardens the public API.
- **`webService.url`** must be `https://`. Previously any URL shape was accepted. Apple PKPass spec requires HTTPS; we now enforce at the schema layer instead of relying on device-side rejection. Same enforcement applies to `semantics.homepage`, `semantics.orderManagementUrl`, and all image URLs.
- **`applyRaw.apple`** cannot override identity fields (`passTypeIdentifier`, `teamIdentifier`, `serialNumber`, `authenticationToken`, `webServiceURL`). **`applyRaw.google`** cannot override `id`, `classId`, `state`. Prevents accidental identity forgery when callers pipe semi-trusted input through the escape hatch.
- **Google save-link JWTs** now include an `exp` claim by default (15 minutes). Override via `GoogleSaveOptions.expirySeconds`, or opt out with `expirySeconds: null`. Non-integer / non-positive values throw.
- **`classSuffix` / `objectSuffix`** validated against Google's allowed charset `[A-Za-z0-9._-]` with a 100-char cap. Prior behavior silently produced JWTs that Google rejected with an opaque error.
- **Image bytes** capped at 5 MiB per source. **PEM input** capped at 100 KiB. Prevents edge-runtime OOM via attacker-controlled input size.

**Public API additions:** `DEFAULT_GOOGLE_JWT_EXPIRY_SECONDS`, `MAX_IMAGE_BYTE_LENGTH`, `MAX_PEM_LENGTH`, `GoogleSaveOptions.expirySeconds`, `GoogleSaveJwtClaims.exp`.

**Other:** Added `SECURITY.md` and `.github/dependabot.yml`.

**Breaking for:**

- Anyone passing `http://` to `webService.url`, image URLs, or semantic URLs (now errors at schema time — switch to `https://`).
- Anyone passing image bytes > 5 MiB (resize before adding to the pass).
- Anyone who was relying on `applyRaw` to override identity fields (use the validated top-level fields instead).
- Anyone using `ZipAssembler.add()` with `..` or backslashes in paths (rarely legitimate).

## 0.1.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/passmint/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "passmint",
"version": "0.1.0",
"version": "0.2.0",
"description": "Edge-native Apple Wallet + Google Wallet pass generation. Web Crypto only.",
"type": "module",
"engines": {
Expand Down