What happened?
First off: not a functional bug - Uniwind Pro works great for us. This is a supply-chain hardening report for the Pro distribution channel.
The uniwind-pro npm package only contains the CLI (12 files, ~29 KB), so npm/pnpm lockfile integrity covers just that. The actual Pro payload - dist/ runtime, cxx/C++, android/ Kotlin, ios/ Swift, nitrogen/ (~888 files) - is downloaded at install time from cdn.uniwind.dev and extracted over node_modules/uniwind with nointegrity verification of any kind:
downloadFromCI in the published CLI does a plain fetch(cdnUrl) → tar extract → copy. No hash check, no signature check, no manifest.
- The payload is also cached unverified in
~/.uniwind/cache/pro/<version> and blindly restored from there on later installs.
- There is nothing to verify against even if we wanted to: no published checksums in the docs or dashboard, no
.sha256/.sig sibling endpoints on the CDN (we probed - 400/404), no Content-Digest/Repr-Digest headers (RFC 9530), no Sigstore/PGP, and If-None-Match is not honored.
Consequence: a compromise of the CDN or your build pipeline would deliver arbitrary native code that gets compiled into our shipped iOS/Android binaries and executed on every dev machine and CI runner. We currently work around this with trust-on-first-use SHA-256 pinning (for reference, the 1.3.0 CI tarball hashes to 433778bcb26b9e7e404a8d1d57f586a4ba1808eb4770e129f7c4e2a7a8ced3b3, ETag/MD5 8099197de53e9beb749433d2218703b8), but that means a manual pin update on every version bump.
You already publish SLSA provenance attestations for the free uniwind package on npm, so the tooling is clearly within reach. Concrete asks, roughly in order of effort:
- A publicly reachable per-version checksum endpoint (e.g.
cdn.uniwind.dev/uniwind-pro/checksums/<version>.sha256). Ideally the CLI then verifies before extracting and before restoring from cache.
Content-Digest/Repr-Digest response headers on the tarball + honoring If-None-Match.
- Longer term: a Sigstore/cosign signature for the payload, or distributing Pro as a private npm package (lockfile integrity + provenance for free).
- Accepting the license token via an
Authorization header - today the token in the URL path is the only auth mechanism (an Authorization: Bearer request 404s), so it ends up in CDN/proxy access logs.
- A
security.txt/documented security contact for reports.
Steps to Reproduce
- Install
uniwind-pro per the docs with a valid CI/CD license token (postinstall downloads https://cdn.uniwind.dev/uniwind-pro/ci/<version>/<token>).
- Inspect
pre/postinstall → install.js → downloadFromCI in the published npm package: plain fetch → tar.x({ strip: 1 }) → copy over node_modules/uniwind; no hash/signature verification; unverified cache restore from ~/.uniwind/cache/pro/<version>.
- Probe for integrity sources next to the tarball URL (
.sha256, .sig, .asc, /checksums/<version>, /manifest.json) → 400/404. Check response headers → no Content-Digest/Repr-Digest; If-None-Match returns 200 instead of 304.
- Check the npm package
uniwind-pro@1.3.0: CLI only (~29 KB) - lockfile integrity never covers the native payload.
Snack or Repository Link (Optional)
No response
Uniwind version
uniwind-pro 1.3.0 (installed via npm alias "uniwind": "npm:uniwind-pro@^1.3.0")
React Native Version
0.85.3
Platforms
Android, iOS, Web
Expo
Yes
Additional information
What happened?
First off: not a functional bug - Uniwind Pro works great for us. This is a supply-chain hardening report for the Pro distribution channel.
The
uniwind-pronpm package only contains the CLI (12 files, ~29 KB), so npm/pnpm lockfile integrity covers just that. The actual Pro payload -dist/runtime,cxx/C++,android/Kotlin,ios/Swift,nitrogen/(~888 files) - is downloaded at install time fromcdn.uniwind.devand extracted overnode_modules/uniwindwith nointegrity verification of any kind:downloadFromCIin the published CLI does a plainfetch(cdnUrl)→ tar extract → copy. No hash check, no signature check, no manifest.~/.uniwind/cache/pro/<version>and blindly restored from there on later installs..sha256/.sigsibling endpoints on the CDN (we probed - 400/404), noContent-Digest/Repr-Digestheaders (RFC 9530), no Sigstore/PGP, andIf-None-Matchis not honored.Consequence: a compromise of the CDN or your build pipeline would deliver arbitrary native code that gets compiled into our shipped iOS/Android binaries and executed on every dev machine and CI runner. We currently work around this with trust-on-first-use SHA-256 pinning (for reference, the 1.3.0 CI tarball hashes to
433778bcb26b9e7e404a8d1d57f586a4ba1808eb4770e129f7c4e2a7a8ced3b3, ETag/MD58099197de53e9beb749433d2218703b8), but that means a manual pin update on every version bump.You already publish SLSA provenance attestations for the free
uniwindpackage on npm, so the tooling is clearly within reach. Concrete asks, roughly in order of effort:cdn.uniwind.dev/uniwind-pro/checksums/<version>.sha256). Ideally the CLI then verifies before extracting and before restoring from cache.Content-Digest/Repr-Digestresponse headers on the tarball + honoringIf-None-Match.Authorizationheader - today the token in the URL path is the only auth mechanism (anAuthorization: Bearerrequest 404s), so it ends up in CDN/proxy access logs.security.txt/documented security contact for reports.Steps to Reproduce
uniwind-proper the docs with a valid CI/CD license token (postinstall downloadshttps://cdn.uniwind.dev/uniwind-pro/ci/<version>/<token>).pre/postinstall→install.js→downloadFromCIin the published npm package: plain fetch →tar.x({ strip: 1 })→ copy overnode_modules/uniwind; no hash/signature verification; unverified cache restore from~/.uniwind/cache/pro/<version>..sha256,.sig,.asc,/checksums/<version>,/manifest.json) → 400/404. Check response headers → noContent-Digest/Repr-Digest;If-None-Matchreturns 200 instead of 304.uniwind-pro@1.3.0: CLI only (~29 KB) - lockfile integrity never covers the native payload.Snack or Repository Link (Optional)
No response
Uniwind version
uniwind-pro 1.3.0 (installed via npm alias "uniwind": "npm:uniwind-pro@^1.3.0")
React Native Version
0.85.3
Platforms
Android, iOS, Web
Expo
Yes
Additional information