2.0 KiB
2.0 KiB
A04: Cryptographic Failures
Last updated: March 1, 2026
Findings addressed
- Production origin could be configured as non-HTTPS.
- JWT configuration did not explicitly constrain issuer/audience/algorithm.
- Missing explicit env contract for JWT issuer/audience values.
Fixes implemented
- Production HTTPS origin enforcement:
- Added production guard requiring
APP_ORIGINto start withhttps://.
- JWT hardening in Fastify:
- Explicit signing algorithm set to
HS256. - JWT signing includes configured
issandaud. - JWT verification enforces:
- allowed algorithm (
HS256) - allowed issuer
- allowed audience
- allowed algorithm (
- Env schema expanded:
- Added
JWT_ISSUERandJWT_AUDIENCEwith secure defaults:skymoney-apiskymoney-web
Files changed
api/src/env.tsapi/src/server.ts.env.exampleapi/tests/cryptographic-failures.test.tsapi/tests/cryptographic-failures.runtime.test.tsapi/vitest.security.config.ts
Verification
Commands:
cd api
npx vitest run -c vitest.security.config.ts tests/cryptographic-failures.test.ts tests/cryptographic-failures.runtime.test.ts
Verified output:
- Test Files:
2 passed (2) - Tests:
7 passed (7)
Dedicated A04 checks in cryptographic-failures.test.ts:
- Production env rejects non-HTTPS
APP_ORIGIN. - JWT issuer/audience defaults resolve as expected.
- Fastify JWT plugin is registered with explicit algorithm + issuer + audience constraints.
Runtime adversarial checks in cryptographic-failures.runtime.test.ts:
- Token with invalid issuer is rejected (
401). - Token with invalid audience is rejected (
401). - Unsigned token (
alg=none) is rejected (401). - Token with valid signature + expected issuer/audience is accepted on protected auth refresh route.
Required production env values
APP_ORIGIN=https://...JWT_SECRETstrong 32+ charsCOOKIE_SECRETstrong 32+ charsJWT_ISSUER=skymoney-api(or your approved value)JWT_AUDIENCE=skymoney-web(or your approved value)