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.
Repository controls are verified, and the production region is evidenced by archived readback; secrets, PITR and other live configuration still require separate readback before release. External pentesting and formal certification are not complete.
Status distinguishes verified repository configuration, supplier documentation and pending production evidence.
Data centres and encryption
Location
The repository configures Cloud Functions for Google Cloud regioneurope-west1 (Belgium, EU), and the same region is the target for Cloud Storage and Firestore. The production region issupported by archived readback dated 2026-09-05: Firestore(default) resides in europe-west1, and all eight production 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 readback covers region only — not PITR, retention or secrets, which remain reported separately below.
Some processors, subprocessors and external services (Stripe, Anthropic, OpenAI, Google Analytics 4 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 stopped and receive no new data until their flow-specific gates have passed. The current journalist connectorsZ-DESK and Z-CRM, however, are permanently stopped in code regardless of generic supplier evidence or configuration flags: 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. The FAS-0 deadline of 2026-08-14 for the account, DPA/SCC and India/United States evidence passed without that evidence being closed, and escalation is under way; optional/new purposes, integrations, features, data categories, bulk workflows and discretionary C3/journalist outreach are STOPPED. The repository CSP permits Sentry's German ingest origin, but the production DSN and event region have not passed live readback; no positive live-region claim is made. 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 — including ADMIN_TOKEN, STRIPE_SECRET_KEYand STRIPE_WEBHOOK_SECRET — are declared asFirebase Secret Manager bindings in the Cloud Functions code (via secrets: […] in functions options and defineSecret()). No secrets are hard-coded in source code or environment files. Cloud Functions v2 reads the values from Google Cloud Secret Manager at runtime. The release gate requires active secret versions for each declared secret to be verified usinggcloud secrets versions list. This revision contains no archived production readback 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 with checkRevoked: true, so a password change or manual revocation can invalidate a session before token expiry. Separate operational endpoints instead use the rotatedX-Admin-Token secret and are not covered by Firebase token revocation.
Admin access
The admin token is rotated manually and is never included in client-side code. Admin endpoints require the X-Admin-Token header with the correct value, verified server-side. No admin operations are accessible from the browser without explicit authentication.
Municipality Licence SSO
The Municipality 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 enabled as an Enterprise SSO add-on.
- 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 the Firestore collection auditLog. The collection 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 are tagged with expiresAt for 2-year retention and deleted asynchronously by Firestore TTL. A live readback on 2026-07-30 reported theauditLog.expiresAt policy 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 null — 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 archived readback in this revision. The release gate requiresgcloud firestore databases describe before PITR may be described as active. 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 | The repository configures Cloud Functions for europe-west1 (Belgium). Firestore resides in europe-west1 and all production buckets in EUROPE-WEST1 or the EU multi-region, supported by archived readback 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 |
| Google Analytics 4 (GA4) | Anonymous visit statistics; only loaded after consent | USA | Consent (Art. 6.1.a); SCC; IP anonymisation enabled |
| Zoho PageSense | Web analytics, A/B testing and heatmaps/session recording on public pages; only loaded after consent | EU script via 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 stopped before flow-specific release. The current journalist connector Z-DESK is permanently stopped in code regardless of generic evidence or flags 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 Municipal Licence P1 support, the municipality is controller and Skolkoll processes under its instructions. Published Zoho terms are not account-incorporation evidence; journalist Z-DESK remains stopped in code. |
| Zoho CRM | The separate lead surface is configured for minimum structured fields but stopped before flow-specific release. The current journalist connector Z-CRM is permanently stopped in code regardless of generic evidence or flags because it uses global email deduplication. Full order free text and Description must not 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; journalist Z-CRM remains stopped in 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 STOPPED. FAS-0 deadline 2026-08-14 passed; only minimised inbound intake continues, while escalation to a lawful replacement channel is under way. Campaigns is governed separately by its own Z-CAMPAIGNS gate | 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 repository CSP permits ingest.de.sentry.io in Germany; the production DSN and event region remain pending live evidence, so no positive live-region claim is made. 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. ANTH-API is subject to a legal country-evidence stop; the repository contains a fail-closed gate, but production deployment and live readback remain pending and no active production stop is asserted as verified | 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 ANTH-API is stopped until the country evidence satisfies the transfer annex's exact approved allowlist contract ["US"] 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 repository implements just-in-time instructions, blocking of street/home-address markers, numbers, contact details and unclear person-like multiword free text, plus a separate minimisation gate for the batch flow. The control reduces risk but does not prove that every permitted short one-word query is non-personal. Production deployment and live readback remain pending. 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. The repository target is a client cache in sessionStorage with at most 20 entries for 24 hours and a separate own GCS batch cache with a 365-day maximum. Active production cache, bucket region and purge readback are not verified. | Legitimate interest (Art. 6.1.f), but both flows are legally stopped for new external requests until their respective operational assessment is approved. The repository makes the gates default-off, 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 gate is explicitly opened. Production deployment and live readback remain pending; no active production stop is asserted as verified. |
| 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). north_europe is only the configured service-region 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 headMaster; while G5 is open and person-role processing is STOPPED, that field is discarded at the earliest mapper boundary 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 repository's Sentry integration is intended to capture application errors in real time when a verified production DSN is active; this revision does not claim that live receipt has been verified. 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 live status 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 extend to the items flagged as open owner input in those documents, which must not be presented as commitments. |
| 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 (release gate, 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 extend to the items flagged as open owner input in the security appendix's hand-over checklist, which is the complete list.
See also: Privacy policy · SLA and uptime · Commercial separation · Transparency