Security #
EthicsPortal handles sensitive whistleblower data. This page documents the specific technical and organizational measures we have in place. It is written for compliance officers, DPOs, and legal teams evaluating the platform.
Last updated: 2026-05-17.
Data encryption #
All sensitive fields are encrypted at rest using Rails ActiveRecord Encryption with non-deterministic encryption (each encryption produces a unique ciphertext, preventing pattern analysis).
| Field | Encrypted | Deterministic |
|---|---|---|
| Report description | Yes | No |
| Reporter name | Yes | No |
| Reporter contact details | Yes | No |
| Message body (reporter–handler communication) | Yes | No |
Non-deterministic encryption means these fields cannot be queried by value at the database level. Even with full database access, an attacker cannot search for a specific reporter name across records.
All connections to EthicsPortal use HTTPS/TLS. Unencrypted HTTP requests are redirected.
Anonymity and privacy #
IP anonymization #
Portal routes (report submission, case lookup, messaging) use a one-way SHA256 hash of the request IP solely for rate limiting. The hash is not reversible — it is not possible to recover the original IP from the stored value.
At the application layer, the reporter’s raw IP address is not stored in the database, and application logs for portal routes are scrubbed to protect whistleblower anonymity.
File metadata stripping #
Uploaded files are automatically stripped of identifying metadata before storage:
| File type | Metadata removed | Method |
|---|---|---|
| Images (JPEG, PNG, TIFF, WebP) | EXIF data: GPS coordinates, camera model, device serial number, author, timestamps | Vips image processing |
| PDF documents | Author, creator application, modification history | exiftool in the standard production setup |
| Video files | GPS, device info, recording software | exiftool in the standard production setup |
| Audio files | Recording device, GPS, software tags | exiftool in the standard production setup |
Metadata removal is performed server-side before storage. For file types handled by exiftool, this depends on the standard production tooling being present.
Virus scanning #
All uploaded files are automatically scanned for malware using ClamAV , an open-source antivirus engine. Scanning happens server-side in a background process after upload. Files that have not passed scanning are blocked from delivery, and infected files are removed automatically.
Files are scanned on EthicsPortal infrastructure — no file data is sent to third-party scanning services.
Handler anonymity #
Whistleblowers never see the real names or email addresses of the people handling their report. All messages from handlers are displayed as “Case handler”. This protects handler identity and prevents social engineering.
No tracking #
EthicsPortal does not use third-party tracking cookies, advertising pixels, or fingerprinting scripts. We use Cloudflare Web Analytics on marketing pages only — it is cookie-free, collects no personal data, and is fully GDPR-compliant. The whistleblower portal itself has no analytics.
Current assurance status #
EthicsPortal does not currently claim ISO 27001, SOC 2, or equivalent certification on this site. It also does not currently publish an independent third-party audit of the anonymity architecture. If that changes, the scope and date will be published here.
Security review materials #
Customers that require procurement or legal review materials can request them during procurement. Available materials may include a signed DPA, registry and tax evidence, a completed security questionnaire, and written answers covering backup and restore procedures, privileged production access, and incident-response handling.
Access control #
Authorization is enforced at the application level using Pundit policies.
| Role | Can view reports | Can manage organization settings | Can assign handlers |
|---|---|---|---|
| Admin | All reports | Yes | Yes |
| Handler | Reports they are assigned to or participating in | No | No |
- Handlers cannot see reports they are neither assigned to nor participating in. Participants are explicitly added by an admin or the primary assignee (for example, looping in legal or HR).
- Reporters have no user account — they access their report via a Case ID (
WB-XXXX-XXXX) plus a 6-digit passcode they choose at submission. - Every controller action checks authorization. Unauthorized access attempts are blocked and logged.
Two-factor authentication #
Handler and admin accounts can enable TOTP-based two-factor authentication via any standard authenticator app (Google Authenticator, 1Password, Authy, and compatible alternatives). Once enabled, sign-in requires both the primary credential and a rotating 6-digit code.
Reporters authenticate with two factors as well: the Case ID (something they hold) and the passcode they chose at submission (something they know). The passcode is stored only as a bcrypt digest and cannot be recovered. The follow-up inbox and message-posting are session-gated behind this check, so a leaked Case ID alone cannot read the report or impersonate the reporter.
Session lifecycle #
Each authenticated session records last_seen_at on every request (debounced). Users can review their active sessions, see when each was last active, revoke any session individually, or sign out of all other sessions at once from the account settings.
Sessions expire automatically after 14 days of inactivity. The next request from an idle session destroys the server-side record, clears the cookie, and forces re-authentication via a fresh magic link. A nightly job sweeps abandoned sessions on the same timeout, so user_agent and ip_address are not retained beyond the idle window even when the user never returns.
Magic-link authentication limits the blast radius of long-lived sessions: a stolen session cookie does not yield a reusable credential, and re-authentication requires email access.
Member access and offboarding #
Organization access is enforced at the request boundary. When a member is deactivated:
- Access to the organization is rejected immediately, including on previously bookmarked URLs.
- Open report assignments are unassigned.
- Participantships are removed.
- The audit-log history attributable to the member is preserved.
- The deactivated member is notified.
- Reactivation does not automatically restore prior case access.
The last active admin and the organization owner cannot be deactivated. All deactivation and reactivation events are written to the append-only audit log.
Memberships with no compliance footprint (no audit-log entries, no assignments, no participantships) are hard-deleted on removal; memberships with a footprint are soft-deactivated so the audit trail remains resolvable.
Rate limiting #
Public portal endpoints are rate-limited to prevent abuse and enumeration attacks:
| Endpoint | Limit |
|---|---|
| Report submission | 5 per 10 minutes per anonymized IP |
| Case lookup (Case ID + passcode) | 10 per 3 minutes per anonymized IP |
| Message submission | 10 per 3 minutes per anonymized IP |
Rate limiting uses the one-way IP hash described above — no actual IP is stored.
Audit and compliance #
Append-only audit trail #
Every action in EthicsPortal is logged with:
- Timestamp (UTC)
- Actor (which user or system process performed the action)
- Action type (report created, status changed, message sent, handler assigned, report viewed, report exported, report deleted, etc.)
Audit log entries are append-only. They cannot be edited or deleted by any user, including organization admins. The full audit trail is included in PDF case exports for regulatory review.
Data retention #
Organizations configure their own retention period: 12, 24, 36, or 60 months after a report is closed. When the retention period expires, the report and all associated data (messages, attachments, audit log entries) are automatically and permanently deleted by a background job.
This satisfies GDPR storage limitation requirements (Art. 5(1)(e)) and Directive 2019/1937 record-keeping obligations (Art. 17–18).
CSRF protection #
All form submissions are protected against cross-site request forgery using Rails’ built-in CSRF tokens.
Secure development lifecycle #
EthicsPortal follows a documented development lifecycle for changes that touch the Service. The stages are stated here so a procurement reviewer can map them to ISO/IEC 27001:2022 controls A.8.25–A.8.29 (see the control map for the full mapping).
| Stage | Practice |
|---|---|
| Architecture and design | Features that introduce new personal-data flows, sub-processors, or authorization scopes are evaluated against the encryption, access-control, and audit-trail commitments documented on this page before implementation. |
| Code review | Production changes are reviewed against a written security checklist (encryption coverage, authorization scope, audit-log emission, input validation, secret handling) before deploy. Static analysis runs on every change and blocks merge on failure. |
| Secure coding | The codebase uses framework-level defenses by default — parameterized queries via ActiveRecord, strong parameters, output escaping in views, CSRF tokens, attribute-level encryption, Pundit authorization at the controller boundary. Deviations require a written justification. |
| Security testing in development | Static analysis (Brakeman
, bundler-audit
, importmap audit) runs on every change. Tests cover authorization paths, encryption-at-rest invariants, audit-log emission, and rate-limit enforcement. See dependency and patch management
for the full toolchain. |
| Environment separation | Production and non-production environments are isolated. No production personal data is used outside production; staging and development use synthetic fixtures. |
| Vulnerability response | Reports acknowledged within 2 business days (see responsible disclosure ). Targets: critical issues remediated within 7 days, high within 30, medium within 90. Confirmed issues affecting deployed customers are reported through the incident register when they meet the register’s scope criteria. |
Dependency and patch management #
EthicsPortal does not deploy end-of-life software components. The application runs on actively supported releases of Rails, Ruby, PostgreSQL, and the underlying operating system; upstream security releases are applied on a rolling basis.
Dependencies are scanned continuously in continuous integration:
- Brakeman flags Rails-specific vulnerabilities on every change.
- bundler-audit checks the Gemfile against the Ruby Advisory Database on every change.
importmap auditscans JavaScript imports for known vulnerabilities on every change.- Dependabot opens pull requests weekly for outdated Ruby gems and GitHub Actions, grouped by minor/patch updates.
Components reaching end-of-life upstream are replaced or upgraded before their support window closes.
Infrastructure #
| Component | Provider | Location |
|---|---|---|
| Application server and database | Hetzner | Nuremberg, Germany (EU) |
| File storage | Hetzner Object Storage | Nuremberg, Germany (EU) |
| Transactional email | Mailjet | France (EU) |
| Payment processing | Stripe | EU |
- All primary data processing occurs within the European Union.
- No credit card numbers or payment credentials are stored on EthicsPortal servers. All payment data is handled by Stripe.
- Mailjet is used for transactional email (handler notifications, not whistleblower-facing). Mailjet is based in France and processes all data within the EU.
- The marketing site is served via Cloudflare (CDN, United States); the reporting and handler portals are not. See the subprocessors page for the full list and transfer safeguards.
Backups and restore #
EthicsPortal operates two complementary backup layers, both retained within the EU:
| Layer | What | Where | Retention |
|---|---|---|---|
| Database | Daily encrypted PostgreSQL dumps via a Kamal accessory | Hetzner Object Storage, Nuremberg (EU) | 7 days |
| Server | Full disk snapshots of the application host | Hetzner Cloud, Nuremberg (EU) | 7 days |
Recovery objectives. Recovery point objective (RPO) is 24 hours. Recovery time objective (RTO) is 4 hours. These objectives also appear in the service level agreement .
Restore testing. A restore drill is executed at least quarterly into a disposable environment. Last drill: 2026-05-14.
Encryption. Database dumps are encrypted at rest by Hetzner Object Storage; application-layer fields encrypted under Rails ActiveRecord Encryption remain encrypted in the dump.
Operational review #
Some operational materials are shared during procurement review rather than published in full on the open web, because they contain infrastructure and response detail that is more appropriate for controlled disclosure.
Topics available on request during procurement include:
- Privileged production-access summary
- Incident-response workflow and escalation contacts
- Business continuity and customer offboarding/export responses
Responsible disclosure #
If you discover a security vulnerability in EthicsPortal, please report it to security@ethicsportal.eu . We ask that you:
- Do not publicly disclose the vulnerability before we have had a chance to address it.
- Provide enough detail for us to reproduce and fix the issue.
- Do not access or modify other customers’ data.
We will acknowledge your report within 2 business days and aim to resolve confirmed vulnerabilities promptly.
Last updated: