This assessment maps claimio's security controls against the Baseline Informatiebeveiliging Overheid (BIO) and ISO 27001:2022 Annex A controls relevant to a SaaS platform processing personal data.
Legend: ✅ Implemented | 🔶 Partial | ❌ Not Implemented | ➖ N/A
| Ref | Control | Status | Notes | |-----|---------|--------|-------| | A.5.1 | Information security policies | 🔶 | CLAUDE.md defines development rules; formal policy document not yet created | | A.5.2 | Information security roles and responsibilities | 🔶 | Defined in code (roles); HR documentation pending | | A.5.14 | Information transfer | ✅ | TLS enforced; API key authentication for auditPic integration | | A.5.23 | Information security for use of cloud services | ✅ | TransIP VPS + Object Store; DPA assessment in progress | | A.5.30 | ICT readiness for business continuity | ✅ | BCDR plan; automated backup verification |
| Ref | Control | Status | Notes | |-----|---------|--------|-------| | A.6.1 | Screening | 🔶 | Informal for current small team | | A.6.3 | Information security awareness, education and training | ❌ | Planned Q4 2026 | | A.6.8 | Information security event reporting | ✅ | Incident handling procedure defined |
| Control | Status | Notes |
|---------|--------|-------|
| DB limited user (claimio_app, DML-only) | ✅ | Implemented in scripts/init-db.sql |
| Flyway uses separate admin user (claimio) | ✅ | Separate credentials for DDL |
| k8s non-root containers | ✅ | runAsNonRoot: true, runAsUser: 1000 |
| k8s read-only filesystem | ✅ | readOnlyRootFilesystem: true |
| Dropped Linux capabilities | ✅ | capabilities.drop: [ALL] |
| Control | Status | Notes |
|---------|--------|-------|
| Branch protection on main / develop | 🔶 | CI required; code review recommended but not enforced |
| No secrets in source code | ✅ | All secrets via env vars; Sealed Secrets in git are encrypted |
| Control | Status | Notes |
|---------|--------|-------|
| Secure password storage (bcrypt) | ✅ | Spring Security BCryptPasswordEncoder |
| JWT short-lived tokens (24h) | ✅ | Access token TTL: 24h |
| Refresh token rotation | ✅ | Single-use refresh tokens; rotation on use |
| Rate limiting on auth endpoints | ✅ | Bucket4j/Redis: login 5 req/min, register 5 req/min, claim POST 10 req/min per IP |
| JWT key rotation support | ✅ | JWT_PREVIOUS_SECRET for zero-downtime rotation |
| Control | Status | Notes |
|---------|--------|-------|
| OWASP dependency-check | ✅ | failBuildOnCVSS=7 in pom.xml |
| OWASP ZAP baseline scan | ✅ | zap-scan.yml runs after every CI build on develop/main |
| SpotBugs + PMD + Checkstyle | ✅ | Static analysis in Maven build |
| Container image scanning | ✅ | Trivy scan job in ci-backend.yml — CRITICAL/HIGH fail build; SARIF uploaded to GitHub Security tab |
| Control | Status | Notes |
|---------|--------|-------|
| Automated data retention/anonymisation | ✅ | Nightly DataRetentionService — configurable per tenant |
| Retention period (default 7 years) | ✅ | Dutch insurance regulation; configurable per tenant |
| Anonymisation preserves audit skeleton | ✅ | PII fields nulled; claim ID/status/dates retained |
| GDPR Art. 17 deletion request support | 🔶 | Manual process; no self-service deletion endpoint yet |
Gap: Implement claimant self-service data deletion endpoint. Due: Q3 2026.
| Control | Status | Notes |
|---------|--------|-------|
| PII fields encrypted at rest (AES-256-GCM) | ✅ | EncryptedStringConverter on all PII columns |
| Email blind index (HMAC-SHA256) | ✅ | EmailHashService — email not searchable in plaintext |
| IBAN masked in UI responses | 🔶 | Stored encrypted; API response exposes plaintext to authenticated users (intended) |
| Control | Status | Notes |
|---------|--------|-------|
| API returns only necessary fields (DTOs) | ✅ | ClaimResponse, AuthResponse — no entity exposure |
| Logs do not contain PII | ✅ | PiiMaskingConverter registered as %msg in logback-spring.xml; scrubs emails, IBANs, Dutch licence plates, BSN from all log output |
| Control | Status | Notes |
|---------|--------|-------|
| TLS enforced on ingress | ✅ | cert-manager + Let's Encrypt; ssl-redirect: "true" |
| Internal service communication | ✅ | ClusterIP services only; no NodePort exposures |
| Network policies | ✅ | k8s/templates/network-policy.yaml — ingress from nginx only; egress to postgres, redis, auditPic, kube-dns only |
| Control | Status | Notes |
|---------|--------|-------|
| Encryption algorithm standards | ✅ | AES-256-GCM (PII), HMAC-SHA256 (email hash + photo signing), HS256 (JWT) |
| Key length ≥ 256 bits | ✅ | 256-bit keys enforced in EncryptedStringConverter constructor |
| Key storage | ✅ | 1Password → Bitnami Sealed Secrets → k8s environment variables |
| Key rotation procedure | ✅ | rotate-secrets.yml GitHub Actions workflow |
| Ref | Control | Status | Notes | |-----|---------|--------|-------| | A.8.25 | Secure development lifecycle | ✅ | Branch protection, CI required, PR validation | | A.8.26 | Application security requirements | ✅ | OWASP Top 10 addressed; ZAP in CI | | A.8.27 | Secure system architecture | ✅ | DTO boundaries, layered architecture, no entity exposure | | A.8.28 | Secure coding | ✅ | SpotBugs, PMD, Checkstyle; Bean Validation on all inputs | | A.8.29 | Security testing in dev and acceptance | ✅ | OWASP ZAP, dependency-check, unit tests (90% branch coverage) | | A.8.31 | Separation of environments | 🔶 | Separate staging namespace; same VPS (not separate infrastructure) |
| # | Gap | Priority | Due | |---|-----|----------|-----| | 1 | Claimant self-service data deletion endpoint | Medium | Q3 2026 | | 2 | Information security policy document | Medium | Q2 2026 | | 3 | Security awareness training | Low | Q4 2026 | | 4 | Branch protection: mandatory code review | Low | Q2 2026 |
| Version | Date | Author | Changes | |---------|------|--------|---------| | 1.0 | 2026-03-30 | GloryLabs | Initial version | | 1.1 | 2026-04-14 | GloryLabs | Close gap #3: PiiMaskingConverter implemented (log PII scrubbing). Update rate-limit figures (5/5/10 req/min). Dependabot active. | | 1.2 | 2026-04-17 | GloryLabs | Close gap #1: Trivy CI scan added. Close gap #2: Kubernetes NetworkPolicy added. |
Reacties