Security and Data Protection
Check security status, data location, subprocessors, incident process and DPA evidence.
Quick check
Region, encryption, secrets, SSO, audit logs, incident routines and contract documentation.
The controls in our code are verified, and the production region is evidenced by an archived check of the production environment; secrets, PITR and other production configuration must still be checked separately before release. External pentesting and formal certification are not complete.
Status distinguishes verified configuration in our code, supplier documentation and checks in production that have not yet been made.
Data centres and encryption
Location
Our configuration places Cloud Functions in Google Cloud regioneurope-west1 (Belgium, EU), and the same region is the target for Cloud Storage and Firestore. The production region issupported by an archived check of the production environment dated 2026-09-05: Firestore's default database resides in europe-west1 (Belgium), and all eight production storage buckets reside in europe-west1 or the EU multi-region. Firebase Hosting is delivered through a global CDN and therefore does not have the same regional boundary. Firebase Authentication is covered by Google Cloud DPA/SCC/DPF. The check covers region only — not PITR, retention or secrets, which remain reported separately below.
Some processors, subprocessors and external services (Stripe, Anthropic, OpenAI and social login providers) may process data outside the EU/EEA. Depending on the recipient country and recipient, an adequacy decision, the DPF or EU Standard Contractual Clauses (SCCs) apply together with the relevant supplier DPA. Zoho PageSense is loaded via the EU script cdn-eu.pagesense.io. Zoho publishes standard DPA/SCC terms, but account incorporation, live tenant region/plan and the focused transfer note remain unverified and are quarterly evidence checks. Separate Zoho Desk support and CRM lead surfaces are configured but switched off and receive no new data until their flow-specific preconditions are met. The current journalist connectors to Zoho Desk and Zoho CRM, however, are permanently switched off in the software code and cannot be switched on by generic supplier evidence or settings: the Desk contact has no case lifecycle and the CRM contact uses global email deduplication. Full order content must not be used as a fallback. Any future replacement must be order-bound with tested minimisation and deletion. Zoho Mail has no positive release: new user-initiated inbound enquiries may be received, manually assessed and answered only to the strictly necessary extent after matter-specific content and necessity minimisation under the dated interim-risk restriction; content is not sent to AI. Our internal deadline of 2026-08-14 for the account, DPA/SCC and India/United States evidence passed without that evidence being completed, and escalation is under way; optional/new purposes, integrations, features, data categories, bulk workflows and discretionary outreach to enquirers and journalists are not permitted. The website's security settings (CSP) permit error reports to Sentry's intake in Germany, but we have not checked in the production environment whether error monitoring is switched on or in which region events are received; no actual region is claimed. See thesubprocessors and external services table below for the full overview, and Data protection and subprocessors for operational detail.
Encryption at rest
Firestore and Cloud Storage encrypt all data at rest using Google-managed keys (AES-256) by default. We do not currently use customer-managed encryption keys (CMEK) — this is a feature we are evaluating for future Pro-tier commitments.
Encryption in transit
All traffic to and from Skolkoll uses TLS 1.2 or later. Firebase Hosting automatically enables HSTS (HTTP Strict Transport Security), preventing downgrade to unencrypted HTTP. Certificates are managed automatically by Google and renewed without manual intervention.
Secrets and authentication
Secrets management
All secrets — among them the administrator key and Stripe's API key and webhook key — are declared per function in the Cloud Functions code as bindings toFirebase Secret Manager. No secrets are hard-coded in source code or environment files. Cloud Functions v2 reads the values from Google Cloud Secret Manager at runtime. Before release, the active versions of each declared secret must be checked directly in the production environment. This revision contains no archived check of that kind and therefore does not assert that all active versions have already been verified.
ID token revocation
Protected admin endpoints use two explicit models. Endpoints based on Firebase ID tokens verify them and at the same time check that the sign-in token has not been revoked, so a password change or manual revocation can invalidate a session before token expiry. Separate operational endpoints instead use a separate, rotated administrator key sent in its own HTTP header and are not covered by Firebase token revocation.
Admin access
The administrator key is rotated manually and is never included in client-side code. Admin endpoints require the administrator key with the correct value in its own HTTP header, verified server-side. No admin operations are accessible from the browser without explicit authentication.
Municipal Licence SSO
The Municipal Licence uses Firebase Authentication as its account store. The standard flow is email-based sign-in and organisation invitations. For municipalities that require central identity management, SAML 2.0 or OIDC can be agreed as a separate add-on. SSO is not part of any Municipal Licence tier.
- IdP options: SAML 2.0 or OIDC, including Microsoft Entra ID / Azure AD.
- Role mapping: The municipality's IdP controls the identity; Skolkoll stores the role and organisation membership for authorisation in the service.
- Offboarding: When the municipality removes the user in its IdP, new sign-in stops. Existing Firebase sessions can be revoked manually if needed.
- Onboarding: Metadata exchange, a test account and domain verification are required before going live.
See also SSO status in the procurement pack.
Audit logging
Sensitive administrative operations are logged in our audit log in the database (Google Cloud Firestore). The log has deny-all Firestore Security Rules — no client can read or write to it. Access is exclusively via Firebase Admin SDK (server-side), eliminating the risk of manipulation through client code.
Each audit log entry contains: timestamp, operation, performing identity, and affected object. New entries get a deletion date stored on the record, 2 years ahead, and are deleted asynchronously by Firestore's automatic deletion (TTL). A check of the production environment on 2026-07-30 showed the deletion rule for the audit log's deletion date as active; this proves policy state, not deletion of a particular expired sample.
For each eligible processed Kollen chat request, the server makes at most one asynchronous write attempt to a separate entry. The response does not await that write, failures are logged, and storage is therefore not guaranteed. The entry uses a keyed, domain-separated HMAC-SHA-256 pseudonym of the IP address truncated to 16 hexadecimal characters, question/answer length, and context as an exact eight-digit school-unit code or no value — never question or answer content. Pseudonymisation happens at write time; the deletion routine for these entries is documented inData protection and subprocessors.
Backup and recovery
Point-in-Time Recovery (PITR) is the target for the Firestore database. When enabled, Google Cloud provides point-in-time restore within its available window (up to 7 days). Actual production PITR status and retention are not supported by an archived check in this revision, and PITR is not described as active until it has been checked directly in the production environment. Recovery has not been exercised in a controlled disaster-recovery drill — we intend to run such a drill ahead of the first Municipal Licence production deployment.
Subprocessors and External Services
The following list mixes actual data processors/subprocessors with external data sources and APIs that do not always process personal data on Skolkoll's behalf. The binding subprocessor register for DPA purposes is available onData protection and subprocessors.
| Service | Role / function | Location | GDPR role / basis |
|---|---|---|---|
| Firebase / Google Cloud | Hosting, database (Firestore), Cloud Functions, Secret Manager, Cloud Storage | Our configuration places Cloud Functions in europe-west1 (Belgium). Firestore resides in europe-west1 and all production storage buckets in europe-west1 or the EU multi-region, supported by an archived check of the production environment dated 2026-09-05. Firebase Hosting: global CDN. Firebase Authentication is covered by Google Cloud DPA/SCC/DPF. | Contract (Art. 6.1.b); DPA included in Firebase terms |
| Stripe | Payment processing for Pro services; card data is never handled by Skolkoll | Ireland (EU) primarily; some fraud-detection functions may involve Stripe US under SCC | Contract (Art. 6.1.b); Stripe DPA; SCC where needed |
| Zoho PageSense | Web analytics, A/B testing and heatmaps/session recording on public pages; only loaded after consent | EU script via the EU address cdn-eu.pagesense.io; account incorporation, live tenant region/plan and the focused transfer note remain unverified and are quarterly evidence checks | Consent (Art. 6.1.a); Zoho publishes standard DPA/SCC terms, not a verified account result |
| Zoho Desk | The separate support surface is configured but switched off before flow-specific release. The current journalist connector to Zoho Desk is permanently switched off in the software code and cannot be switched on by generic evidence or settings, because the contact has no case lifecycle. Full order free text must not be used as a fallback; a future replacement must be order-bound with tested minimisation and deletion | Zoho publishes an EU-hosted Desk endpoint and standard DPA/SCC terms; account incorporation, live tenant region/plan and the focused transfer note remain unverified and are quarterly evidence checks | For a user-initiated enquiry in Skolspegeln's own support flow, Art. 6.1.b applies only where the data subject personally is the prospective contracting party and requests pre-contractual steps; otherwise documented Art. 6.1.f is limited to necessary manual receipt, case-specific minimisation and response. Unexpected third-party or Article 9/10 data requires a separate basis/condition or is not processed further. In support under the Municipal Licence (processing activity P3 in the record of processing: support and incident cases handled on the municipality's behalf), the municipality is controller and Skolkoll processes under its instructions. Published Zoho terms are not account-incorporation evidence; the journalist connector to Zoho Desk remains switched off in the software code. |
| Zoho CRM | The separate lead surface is configured for minimum structured fields but switched off before flow-specific release. The current journalist connector to Zoho CRM is permanently switched off in the software code and cannot be switched on by generic evidence or settings, because it creates one global contact per email address. Neither full order free text nor Zoho CRM's free-text description field may be used as a fallback; a future replacement must be order-bound with tested minimisation and deletion | Zoho publishes an EU API endpoint and standard DPA/SCC terms; account incorporation, live tenant region/plan and the focused transfer note remain unverified and are quarterly evidence checks | For a user-initiated lead/demo enquiry, Art. 6.1.b applies only where the data subject personally is the prospective contracting party and requests pre-contractual steps; otherwise documented Art. 6.1.f is limited to necessary manual receipt, case-specific minimisation, response, abuse prevention and operational recovery. Unexpected third-party or Article 9/10 data requires a separate basis/condition or is not processed further. Separate marketing consent applies only to that purpose. Storage, order handling and contact response for the journalist form instead rely on form consent; Art. 6.1.f there covers only abuse prevention and operational recovery, not the CRM purpose. Published Zoho terms are not account-incorporation evidence; the journalist connector to Zoho CRM remains switched off in the software code |
| Zoho Mail | Dated interim-risk restriction with no positive release: new user-initiated inbound enquiries may be received, assessed manually and answered only to the strictly necessary extent after matter-specific content, necessity and minimisation review; no AI. Proactive/discretionary outreach, campaign/relationship sends, automation, bulk and new integrations, features or data categories in Mail are not permitted. The internal deadline of 2026-08-14 has passed; only minimised inbound intake continues, while escalation to a lawful replacement channel is under way. Campaigns is governed separately by its own preconditions | Zoho One; an account-specific article 28 processor agreement was signed on 2026-09-11, but the Chapter V mechanism remains supplier-asserted and the focused India/United States assessment has not been made. Export, minimisation and verified deletion are permitted; no Chapter V or tenant-level technical compliance is claimed | Legal obligation (Art. 6.1.c) where a specific duty applies. Art. 6.1.b is used only where the data subject is personally a prospective contracting party; otherwise documented Art. 6.1.f is limited to reading, minimising and answering the user-initiated enquiry. Free text is not assumed to be public; Article 9/10 data requires a separate basis or is not processed further |
| Sentry | Error monitoring; collects error messages, stack traces, browser/OS info and IP address that is anonymised shortly after receipt | The website's security settings (CSP) permit intake via ingest.de.sentry.io in Germany; we have not checked in the production environment whether error monitoring is switched on or in which region events are received, so no actual region is claimed. SCCs apply to any support by the US team. | Legitimate interest (Art. 6.1.f); Sentry DPA; SCC for any US support access |
| Anthropic (Claude API) | Intended direct data processor for the AI assistant Kollen. Requests to Anthropic are subject to a legal stop pending evidence of the processing country; the code stops the requests when the evidence is missing, but we have not yet confirmed that this block is deployed and working in the production environment | API data is stored in the United States; the provider also states selected processing locations in Europe, Asia and Australia without a complete country list. No other non-EEA country is currently approved. | Legitimate interest (Art. 6.1.f) under Kollen LIA v1.3, but requests to Anthropic are stopped until the country evidence matches exactly the transfer annex's approved country list, which today covers only the United States, and every actual recipient is covered by adequacy, the DPF or SCCs with a country- and recipient-specific TIA. The Anthropic DPA applies; no blanket ZDR agreement is required. API content is normally deleted within 30 days; flagged content may be retained for up to 2 years and trust-and-safety classifications for up to 7 years, or longer when required by law. |
| OpenAI | Chalkboard-style transformation of school images under OpenAI's safety/content policies: submitted images after explicit consent, or separately imported licensed images after a positive editorial check of the rights and absence of identifiable people. There is no separate moderation purpose or additional model call. Contact details, photographer name, rights-holder name, source links, photo dates and free-text notes are not sent to OpenAI. | EU and applicable third countries under the current transfer annex, including the USA | Consent (Art. 6.1.a) for submitted-image AI choices; legitimate interest (Art. 6.1.f) for rights-controlled imported images and necessary provenance; OpenAI DPA; adequacy decision, DPF or SCC depending on the recipient country. Chalk-style transformation of rights-controlled images without identifiable people does not require a blanket ZDR agreement. |
| Resend | Email delivery for school alerts and transactional mail | USA | Legitimate interest / consent (Art. 6.1.f/a); SCC |
| Nominatim (OpenStreetMap) | Two bounded geocoding flows. The code shows an instruction by the search field, blocks street/home-address markers, numbers, contact details and unclear person-like multiword free text, and has a separate minimisation check for the batch flow. The control reduces risk but does not prove that every permitted short one-word query is non-personal. We have not yet confirmed that this is deployed and working in the production environment. Browser geolocation is unaffected and does not use Nominatim. | OSMF's public Nominatim service is the external recipient. The provider's actual raw-log countries and raw-log retention remain unresolved. Our setting is a client cache in the browser's session storage (sessionStorage) with at most 20 entries for 24 hours and a separate batch cache in our own Google Cloud storage bucket with a 365-day maximum. We have not checked in the production environment that the cache is active, in which region the bucket is located or that purging works. | Legitimate interest (Art. 6.1.f), but both flows are legally stopped for new external requests until their respective operational assessment is approved. Both flows are off by default in the code, with at least 1.1 seconds between client requests and one global single-thread batch queue with at least 15 seconds between starts when the batch flow is expressly activated. We have not yet confirmed that the switch-off is deployed and working in the production environment. |
| ResRobot (Trafiklab) | Public transport data for commute tab; coordinates proxied via Skolkoll's server | Sweden (EU) | Legitimate interest (Art. 6.1.f) |
| JobTech (JobEd Connect) | User-initiated occupation matching when the Career tab is opened. Only hard-coded programme keywords or a public programme name are sent; the recipient also receives the visitor's IP and request metadata. No user-entered free text is sent. | The legal direct recipient is the Swedish public authority Arbetsförmedlingen (the Swedish Public Employment Service). The service's configured region designation for Northern Europe is only a label and is not evidence of a physical processing or access country. | Legitimate interest (Art. 6.1.f); the Swedish Public Employment Service is treated as an independent controller for receipt and, in that role, is responsible for any later provider processing. Approval is limited to this scope; a role change, free personal text or a changed direct recipient stops the flow for reassessment. JobEd-specific raw-log retention is reviewed annually. |
| Skolverket API | Public school-data source. The detail request itself sends only the school-unit code and no person field. Depending on the endpoint, the source response may contain personal data including the head-teacher name field; as long as our assessment of named person roles is not concluded and such processing is paused, that field is discarded at the first processing step and must not be stored, indexed, materialised or included in history. | Sweden (EU) | Public-source status does not make names non-personal data. Current processing is limited to name-free school data; legacy names may be handled only for documented cleanup and rights handling. Any future person-role flow requires a separate decision and is not opened by source access. |
Incident response
We are a small team and want to be honest about our process: we do not have a formal Security Operations Centre (SOC) or 24/7 on-call rotation. What we have is a defined process that we follow consistently.
- Monitoring and detection: The website's Sentry integration is intended to capture application errors in real time when error monitoring is switched on in production; this revision does not claim that we have checked that Sentry actually receives error reports. The Google Cloud console has alerting for unusual CPU spikes, quota overruns, and auth errors. The Sentry dashboard is reviewed under the operating procedure while the integration is active.
- Triage (within 24 hours): When a possible security incident is detected, the responsible developer performs an initial classification: does the incident affect personal data? Is the service unavailable? Are there signs of unauthorised access?
- Containment and mitigation: Depending on the incident type, immediate action is taken — revoking compromised tokens, blocking suspicious IP addresses, or temporarily disabling the affected feature.
- Notification: For processing where Skolspegeln is the controller, we notify the Swedish Data Protection Authority (IMY) without undue delay and, where feasible, within 72 hours only when the breach is likely to result in a risk to data subjects' rights and freedoms (GDPR Art. 33(1)). Affected data subjects are contacted when the risk is likely to be high (Art. 34). Where Skolspegeln is a processor, we instead notify the named controller without undue delay under Art. 33(2) and assist its assessment. Notification is via info@skolspegeln.se.
- Recovery: Static pages are rebuilt from source data. Firestore PITR may be used for database impact only after its status in production has been verified and a controlled restore drill has passed. Until then, this page makes no promise of PITR-based recovery; the incident lead uses the actually verified backup or source-rebuild path that is available.
- Post-incident review: After each serious incident we document the root cause, actions taken, and preventive changes internally. Material security improvements are communicated in the release log.
Service status and planned maintenance are published on the status page.
Compliance and certifications
| Standard / requirement | Status | Notes |
|---|---|---|
| GDPR | Evidence available | Privacy policy, consent banner, DPA template, ROPA, subprocessor register and erasure routines are documented. The municipal signing package (DPA, security appendix, continuity answer) is approved for use by a documented decision of 8 August 2026. The approval does not cover the points in those documents that are not yet finalised, and they are not promised in the agreement. |
| SOC 2 Type II | Not certified | We follow SOC 2 principles (security, availability, confidentiality) but have not undergone a formal Type II audit. Certification is being evaluated ahead of large-scale municipal rollout. |
| ISO 27001 | Not certified | ISO 27001 certification has not been obtained. We work systematically with information security but without a formal ISMS implementation. |
| External penetration test | Not conducted | No external security audit of the application has been conducted in 2026. An external pentest is planned ahead of the production launch of the public free-tier API. |
| PCI DSS | Via Stripe | Skolkoll does not handle card data directly. Stripe, which is PCI DSS Level 1 certified, handles all card data. |
Responsible disclosure
If you discover a security vulnerability in Skolkoll, we appreciate you reporting it to us before publishing it publicly. We commit to:
- Acknowledge receipt of your report within 5 working days.
- Keep you informed of the progress of the investigation.
- Fix confirmed vulnerabilities within a reasonable time depending on severity.
- Acknowledge your contribution in the release log if you wish (with your consent).
We currently offer no financial reward (bug bounty), but we take all reports seriously and communicate openly about the outcome of the investigation.
Disclosure policy: We apply a 90-day coordinated disclosure period. If a vulnerability has not been fixed within 90 days of your report, you reserve the right to publish the details. We will communicate proactively if we need more time.
Contact: Send your report toinfo@skolspegeln.se with the subject line "Security disclosure". Include reproduction steps and an assessment of the impact. Please encrypt with our public key if you are handling sensitive information — contact us and we will share it.
Please do not report via GitHub Issues or social media.
DPA and contract documentation
Skolkoll acts as a data processor for municipalities and schools when we process personal data on their behalf within Enterprise or other paid services. We provide a Data Processing Agreement (DPA) adapted for municipal procurement.
- Standard template: See our DPA template for a ready-to-use data processing agreement.
- Custom agreement: Contact info@skolspegeln.se if your organisation requires a tailored DPA.
- ROPA (Record of Processing Activities): Available on the ROPA page.
- Data protection details: See the data protection and subprocessors page for operational GDPR details.
- Security appendix: A source-referenced appendix for municipal security review (checks before production release, stage/production isolation, build integrity and security headers) is provided with procurement responses. The appendix is approved for use in procurement responses by a documented decision of 8 August 2026. The approval does not cover the points in the security appendix's checklist that are not yet finalised.
See also: Privacy policy · SLA and uptime · Commercial separation · Transparency