⚠️ This site is NOT tax advice — it is a tool to help you prepare your own filing. Always verify amounts before submitting.

TaxNinja JP

Security

How we protect your data. We publish this page deliberately so you can verify our posture matches what you expect from a service handling tax-return inputs.

Credentials

  • bcrypt-hashed passwords (cost 10). 8-char minimum, 256-char max.
  • Sign-in on non-existent emails runs a dummy compare to prevent timing-oracle enumeration.
  • Rate limits: 10 sign-ins / 5 min / IP, 5 / 5 min / email; 20 sign-ups / hour / IP.

Sessions

  • HS256 JWT in an httpOnly cookie, SameSite=strict, 30-day expiry.
  • Secure flag set under HTTPS (NODE_ENV=production).
  • JWT_SECRET required at production boot — missing secret is a fatal warning.

Access control

  • Every API route scopes reads and writes by userId; IDs of other users' tax years return 404, not 403, so there is no ID-enumeration signal.
  • Sign-up cannot elevate a user to admin — the role field is whitelisted server-side.
  • Admin-only pages require role === 'admin'.

CSRF & origin checks

Edge middleware rejects cross-origin state-changing API calls via an Origin-header check; SameSite=strict cookies are the secondary defense.

Input validation

  • All yen amounts bound to ±1 trillion and required to be finite integers.
  • Wizard-answer keys whitelisted — blocks prototype-pollution and junk-key storage.
  • UUID path parameters validated — invalid UUIDs 404 rather than 500.

Where your progress data lives

Your in-progress return (residency, postal code, income items, ledger entries, wizard answers, package summaries) is persisted to a PostgreSQL database running in our service's private container network. Nothing is stored in browser localStorage and nothing is sent to third-party backends.

  • Postgres port 5432 is not exposed to the public internet — only the web app container talks to it over an internal network.
  • Every row is tied to your userId. Our API layer scopes reads and writes by session; another user's IDs return 404, not 403 (no enumeration signal).
  • Sensitive fields that cannot be reconstructed (your password) are hashed with bcrypt. Operational fields that must stay queryable (email, name, postal code, wizard amounts) are stored as plain Postgres rows, protected by authentication, authorization, and file-system permissions rather than column-level encryption.
  • Generated tax-package PDFs are rendered on demand and streamed to you; we do not retain the rendered file server-side. Only a summary row (final amount, income total, deduction total) is kept so the admin dashboard and your own dashboard can show "1 package generated on ...".
  • When you delete a tax year, all its income items, ledger entries, and package summaries cascade-delete. When you delete your account (dashboard → Account & privacy), all of the above plus your user row cascade-delete in a single transaction.

My Number handling

  • Collected only with your explicit opt-in, logged in the audit log.
  • Stored encrypted at rest with a key separate from the general application key.
  • Deleted within 24 hours of package generation, or immediately on request.

Reporting a vulnerability

Our public contact channel is being updated. Please check back shortly — the site administrator will publish a security reporting address here once configured.

Not tax advice

This site is NOT tax advice — it is a tool to help you prepare your own filing. Always verify amounts before submitting.