UpSkillZone

Security posture — UpSkillZone

How we keep credentials trustworthy.

This page describes the controls we run today, in production. It is a working document, not a marketing claim — every primitive and parameter listed here corresponds to code in the open-source platform repo and to a key advertised at our public JWKS endpoint.

Vulnerability disclosure

Send security reports to security@upskillzone.com. PGP-encrypt sensitive payloads against the fingerprint below. Acting in good faith under our written safe-harbor policy, you will not be subject to legal action for testing within scope.

initial response
within 1 business day
triage decision
within 5 business days
fix target (high/critical)
30 days
disclosure window
90 days, coordinated
PGP fingerprint
5C1E 7B4D 9A2F 38C0 6E11 BD55 4A87 0F31 D6C9 2A48
public key
/.well-known/security.txt

Full procedure, scope, and exclusions live in the repo at /reference/SECURITY_DISCLOSURE.md. Please do not file vulnerabilities through general support.

Cryptographic primitives

  • Ed25519 for credential signing. Every W3C Verifiable Credential, hire attestation, and 90-day outcome attestation is signed by an Ed25519 issuer key. Verifiers check the proof offline against the public JWKS.
  • SHA-256 for evidence hashes. Submissions, graded artifacts, and rubric snapshots are pinned by their SHA-256 digest before they are referenced from a credential.
  • JCS canonicalization (RFC 8785). Before signing or hashing any JSON document we run JSON Canonical ization Scheme so that whitespace, key order, and number formatting cannot change a verified payload.

Key management

  • In production, the issuer signing key lives in a cloud KMS and is HSM-backed. Private key material never leaves the module; the application calls a sign API.
  • Local development uses a deterministic dev key derived from a documented seed. It is for testing only and is clearly labeled as such in the JWKS metadata.
  • Issuer keys rotate every 90 days. New keys are pre-published to JWKS before they sign anything, so verifiers always have a chance to refresh first.
  • Old keys are retained in JWKS for verification of historically issued credentials. Rotation does not invalidate prior credentials; it only changes which key signs new ones.

Auth tokens

  • Access JWTs are short-lived: 15 minutes, held in memory only on the client. They are never written tolocalStorage.
  • Refresh tokens are 30-day, HttpOnly, SameSite=lax cookies bound to the API origin. JavaScript on the page cannot read them.
  • Refresh rotates on every use: a successful refresh issues a new refresh cookie and invalidates the old one. Reuse of a previously-rotated refresh token is treated as a compromise signal and revokes the session.

Network

  • TLS 1.3 in production, with modern cipher suites only. Older TLS versions are not negotiated.
  • HSTS is enabled on the apex domain with a long max-age and includeSubDomains.
  • All session cookies are SameSite with the Secure flag in production.
  • In development the frontend and backend are served same-origin via Next.js rewrites, so cookie and CSRF behavior in dev matches production rather than relying on cross-origin allowances.

Application

  • Passwords are hashed with argon2id using tuned memory and time costs. We do not store plaintext or reversible password material at any point.
  • Rate limiting is applied per IP and per authenticated user on auth endpoints, write endpoints, and verification endpoints. Excess traffic returns 429 with a retry hint.
  • All write endpoints accept an idempotency key. Replays of the same key within the retention window return the original response instead of double-applying the write.

Data

  • MongoDB is configured with encryption at rest on the storage volume.
  • Backups are encrypted with a separate KMS key from the live database, so a compromise of the live cluster does not also unlock historical snapshots.
  • Where the platform serves multiple tenants, data is logically separated at the document level and queries are scoped through enforced filters in the data layer.

Bug bounty

We do not run a paid bounty programme yet. Researchers who report a confirmed, in-scope vulnerability under the safe-harbor policy can opt into the public credit list below; high-severity finds receive a written reference letter on company letterhead on request.

in scope
upskillzone.com, *.upskillzone.com, the public API at /api/v1/*, the verifier at /verify, and the open-source platform repository.
out of scope
third-party services we rely on (Stripe, RazorpayX, MongoDB Atlas, the cloud KMS), social-engineering attacks against employees, denial-of-service, and findings that depend on a compromised end-user device.
payouts
none today. Status will be updated here when budget lands.

Researcher credit

Researchers who chose to be named after coordinated disclosure. Add your handle by replying to the disclosure-acknowledgement email.

  • No public researchers credited yet. The list is honest about being empty rather than padded with placeholder names.

What we don’t do

A short list of practices that occasionally show up in this space and that we have explicitly chosen not to adopt:

  • No SMS-based 2FA fallback.

    SIM-swap and SS7 attacks make SMS a downgrade channel. We support TOTP and WebAuthn only.

  • No plaintext password emails.

    Password reset always goes through a single-use, short-lived token. We never email a password — set or recovered.

  • No proprietary credential schema.

    Credentials are W3C VC and Open Badges 3.0. There is no UpSkillZone-only format that requires our SDK to verify.

  • No opaque verification.

    Anyone can verify a credential offline against the public JWKS — without an account, an API key, or our cooperation.

See also