Security model
Protections
Section titled “Protections”- Code signing. With a public key configured, the SDK only installs packages whose RS256 signature verifies and whose
contentHashmatches the recomputed package hash.alg: noneand other algorithms are rejected. - Safe extraction. Zip entries that would escape the package directory (zip slip) are rejected on the server and the device;
deletedFilespaths outside the package are ignored; extracted size is capped at 1 GB on devices. - Hidden files can’t bypass verification.
__MACOSX,.DS_Store, and stray signature files are deleted before hashing, so an unverified bundle can’t be smuggled next to a verified one. - Accounts. Passwords are hashed with argon2 (max 256 characters); login takes the same time whether or not the account exists; logins and registrations are rate limited per IP.
- Access keys. 240 random bits, stored as SHA-256, revocable, and expiring (at most 10 years).
- Authorization. Every management route checks app membership; destructive actions (deleting apps or deployments, clearing history, managing collaborators) are owner-only; admin routes check the admin flag.
- Input limits. Lengths are bounded across all schemas; uploads are limited in size, file count, and extracted size; device reports are only recorded for labels that exist, with bounded formats.
- Dashboard. Strict CSP (
script-src 'self',frame-ancestors 'none'),X-Frame-Options,nosniff, andReferrer-Policy. - Container. The server runs as a non-root user.
Accepted risks
Section titled “Accepted risks”- Package URLs are guessable from the hash. Anyone who knows a package hash can download it. Hashes only appear in
update_checkresponses (which need a deployment key), and package contents are sent to every device anyway. Don’t put secrets in your JS or Dart code. - Downgrades with an old, valid package. A signature binds the contents, not the label or target version. Use HTTPS so
update_checkresponses can’t be forged. - Collaborators can release and promote to Production. Only add people you trust.
- CORS is open (
*). Authentication uses a bearer header, not cookies, so there is no CSRF exposure. - Deployment keys appear in request logs.
update_checktakes the key as a query parameter; the key is embedded in apps and is not a secret.
Operating safely
Section titled “Operating safely”- Always serve Patchkite over HTTPS, and enable code signing for production apps.
- Keep the signing private key in your CI’s secret store, not in a repository.
- Give each CI pipeline its own access key with a reasonable TTL, and revoke unused keys.
- Close registration (
ALLOW_REGISTRATION=false) after creating the admin account.
Reporting a vulnerability
Section titled “Reporting a vulnerability”Please report vulnerabilities privately through GitHub’s private vulnerability reporting on the affected repository, not in a public issue.