Secure by Default: CRA Art.12(2) Hardening Guide for SaaS Developers
Post #2 in the sota.io EU ENISA Secure by Design Series
The EU Cyber Resilience Act's Article 12(2) states that products with digital elements must be "placed on the market with a secure default configuration". That sentence carries €15 million in potential liability for SaaS companies that ship with insecure defaults.
In Post #1 of this series, we covered the five pillars of ENISA's Secure by Design framework. This post goes one layer deeper: what does "secure by default" mean in practice, which default configurations expose you to CRA non-compliance, and how do you run a systematic hardening audit before the September 2026 deadline?
The answer is more granular than most compliance checklists suggest. "Secure defaults" under the CRA is not a single configuration — it is a principle applied across authentication, network exposure, data handling, logging, and third-party integrations. ENISA has published specific guidance on each domain. This post maps that guidance to the implementation decisions your engineering team makes today.
What CRA Art.12(2) Actually Requires
Article 12(2) of the CRA reads:
"Products with digital elements shall be placed on the market with a secure default configuration, including the possibility to reset the product to its original state."
This is paired with Article 12(3), which specifies that products shall:
- Protect against unauthorized access by appropriate controls including authentication, authorization, and access management mechanisms
- Protect the confidentiality of stored, transmitted, or otherwise processed data
- Minimize the attack surface including external interfaces
- Be designed, developed, and maintained to limit the impact of an incident using appropriate exploitation mitigation mechanisms and techniques
Reading these together, the CRA's "secure by default" requirement has four operational dimensions:
1. Hardened initial state — the product as shipped (or as provisioned in SaaS terms) must not require the user to take security actions before it is safe. Security configuration should be opt-out, not opt-in.
2. No security-downgrade without explicit consent — convenience features that weaken security (e.g., disabling MFA, enabling HTTP, relaxing password policies) must require deliberate action, not be enabled by default.
3. Reset capability — users must be able to return the product to its secure initial state. This matters for SaaS in the context of tenant isolation: a security-misconfigured tenant should be resettable without data spillage.
4. Proportionality to use case — defaults must be appropriate for the intended use and foreseeably intended misuse. A product marketed to enterprises must apply enterprise-grade defaults even if its consumer edition ships with weaker settings.
ENISA's interpretation in its SbD guidelines (ENISA-GOOD-PRACTICES-SBDI-v1.0, updated Q1 2026) adds one critical gloss: the burden of security must not be placed on the user. If making the product secure requires the user to know what a cipher suite is, the default is not secure.
The Five Secure-by-Default Domains
Domain 1: Authentication Defaults
Authentication is where most SaaS products fail the secure-by-default test. Common insecure default patterns:
| Insecure Default | CRA Impact | Secure Alternative |
|---|---|---|
| Password-only login enabled for admin accounts | Art.12(3)(a) — unauthorized access | MFA required for all admin roles from first login |
| Default passwords (admin/admin, changeme) | Art.12(2) — insecure initial state | Force credential rotation on first access |
| Session tokens with no expiry | Art.12(3)(a) — persistent access vector | 24h max session, 1h idle timeout |
| Password reset via email with no expiry | Art.12(3)(a) — account takeover | 15-minute reset token expiry |
| API keys without scope restriction | Art.12(3)(b) — excess privilege | Keys scoped to minimum required actions |
OAuth redirect URIs: wildcard * | Art.12(3)(a) — redirect attacks | Explicit allowlist, no wildcards |
| "Remember this device" enabled by default | Art.12(2) — security bypass | Opt-in, device trust with audit trail |
ENISA Recommendation — Authentication Defaults:
- Require MFA enrollment at first login for all accounts with admin or data-access privileges
- Enforce password complexity (minimum 12 characters, breach-detection against HaveIBeenPwned or equivalent)
- Set session token expiry no longer than 8 hours for administrative interfaces, 24 hours for user interfaces
- Disable all legacy authentication protocols (Basic Auth over HTTP, OAuth 1.0, password-based SSH root access) unless explicitly re-enabled
CRA Compliance Check — Authentication:
□ No default or static credentials exist in shipped configuration
□ MFA is available and enabled-by-default for admin roles
□ Session tokens expire automatically
□ Password reset tokens have a defined and short TTL
□ API keys require explicit scope selection at creation
□ All admin actions are logged with user identity and timestamp
Domain 2: Network Exposure Defaults
The principle of minimized attack surface (Art.12(3)(c)) directly governs what services a product exposes by default. Every unnecessarily exposed port, protocol, or service is a CRA violation surface.
Insecure network defaults that remain common in SaaS products:
Unrestricted CORS: Many SaaS APIs ship with Access-Control-Allow-Origin: * to simplify developer integration. Under the CRA, this is a default that enables cross-site attacks without user consent. Secure default: allowlist or specific origin enforcement.
Unencrypted internal traffic: Microservices communicating over HTTP internally is common in Kubernetes deployments. CRA Art.12(3)(b) requires confidentiality of transmitted data. ENISA SbD guidance extends this to internal traffic: mTLS or service mesh encryption should be the default.
Debug and management endpoints publicly exposed: /metrics, /health/verbose, /admin, /debug endpoints often expose internal topology, credentials, and performance data. CRA compliance requires these to be either disabled or access-controlled by default.
Wildcard DNS records: *.yoursaas.io DNS pointing to shared infrastructure allows tenant-enumeration and subdomain takeover if any subdomain lapses. Secure default: explicit DNS records per tenant, no wildcards.
Open egress: Default allow-all outbound traffic enables exfiltration and C2 communication. CRA's requirement to "limit the impact of an incident" implies that egress should be restricted to known destinations by default.
ENISA Network Hardening Defaults:
Inbound:
- TLS 1.2 minimum, TLS 1.3 preferred — enforced at load balancer
- HTTP → HTTPS redirect with HSTS preloading (max-age=31536000)
- Cipher suite allowlist: AES-256-GCM, ChaCha20-Poly1305 only
- No SSLv3, TLS 1.0, TLS 1.1
- Public ports: 443 only (plus 22 for management, access-controlled)
Internal:
- mTLS between service mesh components
- Network policies: default-deny with explicit allow rules
- No inter-namespace traffic without explicit policy
Egress:
- Allowlist: known third-party APIs, update endpoints
- Block: Tor exit nodes, known C2 IPs (threat intel feed)
- Rate limit: prevent large-volume data transfers
The EU-Sovereign Infrastructure Wrinkle:
Many SaaS products use US-based CDNs (Cloudflare, Fastly, AWS CloudFront) as their default network edge. ENISA's SbD guidance does not explicitly ban this — but it does require that TLS termination occurs before data leaves your control boundary. If your CDN terminates TLS and has access to plaintext request bodies containing PII, you have a CLOUD Act exposure that ENISA's threat model explicitly covers.
Secure-by-default for EU-exposed data means considering where TLS terminates relative to jurisdictional control. EU-sovereign edge options (Cloudflare EU Data Localization Suite with binding commitments, or EU-native CDN providers like Bunny.net or Gcore) allow you to enforce the CRA's data confidentiality requirements without jurisdictional ambiguity.
Domain 3: Data Handling Defaults
CRA Art.12(3)(b) requires products to "protect the confidentiality, integrity, and availability of data." ENISA translates this into four concrete default requirements for data handling.
Encryption at rest: Data stored in databases, object storage, and backup systems must be encrypted by default. AES-256 is the ENISA minimum. Encryption must use keys the product operator controls — not keys managed solely by the cloud provider. If your default RDS instance uses AWS-managed KMS keys with no customer-managed key option, that default does not meet the spirit of CRA data sovereignty requirements.
Encryption in transit: Already covered in network defaults, but applies specifically to database connections, message queue connections, and backup transfers. Default: require TLS for all external and internal database connections. No sslmode=disable in production configurations.
Data minimization defaults: CRA Art.12(3)(d) requires that products limit data to what is necessary. In practice this means: default logging configurations should not capture request bodies, user-entered data, or session tokens. Many frameworks log full HTTP requests by default — that configuration is not CRA-compliant if it captures personal data unnecessarily.
Retention defaults: Data collected by default must have a defined retention period that is appropriate to the purpose. Audit logs: 90 days minimum (ENISA), 12 months recommended for NIS2-covered entities. Application logs: 30-60 days typical. Personal data: minimum necessary for the service, with automated deletion enforced by default.
Data Classification at Collection:
ENISA SbD guidance introduces the concept of "secure defaults for data collection" — the product should not collect categories of sensitive data without explicit user configuration:
| Data Category | Default Action | User Override |
|---|---|---|
| IP addresses in logs | Anonymize last octet | Allow full logging for abuse-prevention |
| User-agent strings | Truncate to OS/browser | Full UA for analytics |
| Request bodies | Do not log | Allow for debugging with explicit consent |
| User PII | Pseudonymize in logs | Never allow plaintext PII in logs |
| Payment data | Never log, ever | Not overridable |
| Health/biometric data | Separate encrypted store | Requires explicit controller consent |
Domain 4: Logging and Audit Defaults
A product that does not log security-relevant events by default cannot satisfy the CRA's incident response requirements. Article 13(8) requires manufacturers to "address and remediate vulnerabilities without delay" — which requires knowing when something went wrong. That requires logging.
ENISA's SbD guidance specifies a minimum set of security events that must be logged by default:
Authentication events:
- Successful login (user, timestamp, IP, MFA method)
- Failed login attempts (user, timestamp, IP, failure reason)
- MFA bypass events (admin override, backup codes used)
- Password changes and resets
- Account lockout triggers
Authorization events:
- Access to sensitive resources (admin panels, user data exports, API key management)
- Permission escalation (role changes, API scope additions)
- Failed access attempts to restricted resources
Configuration changes:
- Security setting modifications (MFA policy changes, session timeout changes)
- User role and permission changes
- Integration and API key additions/deletions
- Firewall rule or allowlist modifications
Infrastructure events:
- Service restarts and failures
- Certificate expiry warnings (>30 days, >7 days, >1 day)
- Dependency vulnerability alerts
What must NOT be in logs by default:
- Plaintext passwords or password hashes
- Session tokens or API keys
- Request bodies containing PII
- Credit card or payment data
Log Integrity Requirement (ENISA SbD):
Logs that can be modified by a compromised service are insufficient. ENISA SbD guidance recommends that security logs be written to append-only storage (WORM — Write Once Read Many) with cryptographic chaining (each log entry hashes the previous), and that they be replicated to a separate security domain not accessible to the application service role.
For SaaS on EU-sovereign infrastructure, this typically means writing security logs to a separate logging service (Grafana Loki with immutable storage, OpenSearch with index lifecycle policies, or a dedicated SIEM) with strict network isolation from the application tier.
Domain 5: Third-Party Integration Defaults
SaaS products routinely integrate with dozens of third-party services: payment processors, analytics platforms, error tracking, customer data platforms, communication providers. Each integration is a potential attack surface expansion. CRA Art.12(3)(a) requires that "the attack surface including external interfaces" be minimized.
Insecure third-party integration defaults:
Over-privileged OAuth scopes: When adding a Google Workspace or Microsoft 365 integration, many products request the maximum scope set to avoid future re-authorization. The secure default is minimum required scope at integration time, with scope expansion requiring re-authorization.
Third-party scripts in browser context: Marketing tags, analytics scripts, and chat widgets loaded from third-party CDNs run in the same browser context as your application. Without Content Security Policy (CSP) enforcing strict source allowlists, a compromised third-party script can exfiltrate session tokens. Secure default: strict CSP with nonce-based or hash-based script allowlisting.
Webhook reception without signature verification: Receiving webhooks from payment processors or CI/CD systems without verifying the HMAC signature is a default security gap. ENISA SbD: all webhook endpoints must verify origin signatures by default.
Third-party analytics with user PII: Sending user email addresses, names, or internal IDs to analytics platforms by default creates uncontrolled data flows. Secure default: analytics events contain pseudonymized user IDs only, no PII, unless explicitly enabled.
US-based error tracking: Sending stack traces, error context, and request data to Sentry (US), Datadog (US), or similar services by default creates CLOUD Act exposure for any error context that includes EU personal data. EU-sovereign alternatives: GlitchTip (self-hosted), Sentry Self-Hosted on EU infrastructure, Highlight.io with EU region.
The 48-Hour Configuration Audit
If you want a practical starting point for CRA Art.12(2) compliance, this 48-hour audit identifies the highest-impact insecure defaults in your current SaaS product.
Day 1: Discovery (4 hours)
Step 1 — Authentication inventory (1 hour)
# Enumerate all authentication methods enabled in production
# Document for each: is it default-on or requires configuration?
# Flag: anything that allows access without MFA for privileged accounts
# Flag: any API key or service account with no expiry
# Flag: any OAuth application with wildcard redirect URIs
Step 2 — Network exposure scan (1 hour)
# From outside your VPC:
nmap -sV --open <your-production-ip-range>
# Expected result: 443 only (plus jump host if applicable)
# Flag: anything else open
# Test HTTPS configuration:
curl -I https://yoursaas.io
# Expect: Strict-Transport-Security header present
# Expect: X-Content-Type-Options: nosniff
# Expect: X-Frame-Options: DENY or SAMEORIGIN
# Flag: missing security headers
# Test CORS:
curl -H "Origin: https://evil.example.com" -I https://api.yoursaas.io/api/v1/health
# Flag: Access-Control-Allow-Origin: * in response
Step 3 — Default credentials scan (30 min)
# Search codebase and deployment configs for default credentials:
grep -r "password.*=.*admin\|password.*=.*changeme\|password.*=.*default\|secret.*=.*secret" \
--include="*.env*" --include="*.yaml" --include="*.yml" --include="*.json" \
--include="*.conf" --include="*.config" . 2>/dev/null
# Check Kubernetes secrets for plaintext defaults:
kubectl get secrets -A -o json | python3 -c "
import json,sys,base64
d=json.load(sys.stdin)
for item in d['items']:
for k,v in item.get('data',{}).items():
decoded=base64.b64decode(v).decode()
if any(w in decoded.lower() for w in ['password','secret','key','token']):
print(item['metadata']['namespace'], item['metadata']['name'], k, decoded[:20])
"
Step 4 — Logging coverage check (1.5 hours)
# Trigger a test authentication failure and verify it appears in logs:
curl -X POST https://api.yoursaas.io/auth/login \
-d '{"email":"test@example.com","password":"wrongpassword"}'
# Check your logging system for the event within 30 seconds
# Flag: event not present, or present without IP/timestamp/user
# Trigger a test access to a restricted endpoint and verify log entry:
curl -H "Authorization: Bearer invalid_token" \
https://api.yoursaas.io/admin/users
# Verify: unauthorized access attempt appears in security log
# Flag: not logged, or logged without user identity context
Day 2: Remediation Prioritization (4 hours)
Priority 1 — Immediate remediation (do today):
- Any default or static credentials found in configuration
- Any admin interface accessible without MFA
- Any HTTP endpoint that returns data (not just redirect)
- CORS
*on authenticated API endpoints - Missing HSTS header on production domain
Priority 2 — Sprint remediation (next 2 weeks):
- Session token expiry enforcement
- Logging gaps in authentication and authorization events
- Over-privileged API keys and OAuth scopes
- Third-party scripts without CSP enforcement
- Database connections without TLS enforcement
Priority 3 — Roadmap items (before September 2026):
- Log integrity (WORM storage, cryptographic chaining)
- Data classification and automated PII redaction in logs
- EU-sovereign migration for US-exposed data flows
- Automated configuration drift detection
Secure Default Configuration File Template
For SaaS products using environment-variable-based configuration, this template shows a secure baseline. Deploy this as your config.defaults.yml or equivalent — users override individual settings, but start from a hardened baseline.
# CRA Art.12(2) Secure Default Configuration
# Last updated: 2026-05-28 | ENISA SbD v1.0 alignment
authentication:
mfa_required: true # Art.12(3)(a)
mfa_required_for_roles: [admin, owner, billing]
password_min_length: 12 # ENISA SbD §4.1
password_breach_check: true # HaveIBeenPwned API
session_timeout_minutes: 480 # 8 hours for admin sessions
session_idle_timeout_minutes: 60 # 1 hour idle
api_key_expiry_days: 90 # Force rotation
api_key_scope_required: true # No omnipotent keys by default
remember_device: false # Opt-in
legacy_auth_protocols: disabled # No Basic Auth, OAuth 1.0
network:
force_https: true # Art.12(3)(b)
hsts_max_age: 31536000 # 1 year
hsts_include_subdomains: true
hsts_preload: true
tls_minimum_version: "1.2"
tls_preferred_version: "1.3"
cors_allowed_origins: [] # Must be explicitly configured
cors_allow_credentials: false
csp_enabled: true
csp_mode: "strict-nonce" # Nonce-based, no unsafe-inline
data:
encryption_at_rest: true # AES-256-GCM
encryption_key_rotation_days: 90
encryption_in_transit: true # TLS for all DB connections
log_request_bodies: false # Art.12(3)(b) — data minimization
log_pii: false
log_tokens: false
analytics_user_id_pseudonymized: true
data_retention_audit_logs_days: 90
data_retention_app_logs_days: 30
automated_deletion_enabled: true
logging:
security_events_enabled: true # Art.13(8) — incident response
log_auth_success: true
log_auth_failure: true
log_mfa_bypass: true
log_permission_changes: true
log_config_changes: true
log_cert_expiry_warnings: true
log_integrity_mode: "append-only" # ENISA SbD §5.3
log_destination_isolated: true
third_party:
analytics_pii: false # No PII in analytics by default
webhook_signature_verify: true # HMAC verification required
csp_third_party_scripts: false # Explicit allowlist required
oauth_scope_minimum: true # Request minimum scope
debug:
debug_endpoints_enabled: false # Art.12(3)(c)
verbose_errors_enabled: false # No stack traces in responses
metrics_public: false # Auth required for /metrics
Configuration Drift: The Ongoing Compliance Problem
Shipping a secure default configuration is a one-time action. Maintaining it over time is an ongoing engineering discipline. ENISA SbD guidance specifically calls out "configuration drift" — the gradual accumulation of security-weakening deviations from the secure baseline — as a primary failure mode.
Configuration drift happens through:
- Debugging sessions that disable security controls temporarily and are never re-enabled
- Customer requests that weaken security for specific tenants and become default over time
- Dependency updates that change default behaviors silently
- Infrastructure changes that reset configurations to provider defaults
- Developer environments that propagate insecure settings to staging or production
CRA Art.12 implicitly requires ongoing configuration verification, not just a one-time audit. ENISA recommends:
Automated configuration scanning: Tools like kube-bench (Kubernetes CIS benchmarks), checkov (IaC security scanning), and ScoutSuite (cloud configuration auditing) should run on every deployment. Pass/fail thresholds enforced in CI/CD pipeline.
Configuration-as-code with drift detection: All security-relevant configuration stored in version-controlled Infrastructure-as-Code (Terraform, Pulumi, CDK). Drift detection compares live state to declared state on a schedule (daily minimum).
Immutable infrastructure: Container images rebuilt from scratch on each deployment prevent configuration accumulation. Servers that are upgraded in-place are not compliant with ENISA SbD drift prevention guidance.
Tenant configuration auditing: For multi-tenant SaaS, each tenant's security configuration should be auditable against your secure baseline. Tenants that have explicitly weakened defaults (disabled MFA, extended sessions) should be flagged in your compliance dashboard.
What "Reset to Original State" Means for SaaS
CRA Art.12(2) includes an often-overlooked requirement: products must offer "the possibility to reset the product to its original state." For a physical IoT device, this means a factory reset button. For SaaS, it's more nuanced.
ENISA's interpretation for software products (ENISA-CRA-FAQ-2026, Q.47):
"For software-as-a-service products, the manufacturer should provide a mechanism by which the operator can restore the product's security configuration to its default secure state. This does not require deletion of user data — it requires restoration of security parameters to their shipped defaults."
In practice, this means your product should support a security configuration reset that:
- Restores all authentication settings to defaults (MFA required, session timeouts, password policies)
- Resets all network configuration to the hardened baseline (CORS, CSP, TLS settings)
- Revokes all non-essential API keys and OAuth grants
- Disables any custom integrations that were configured
- Does NOT delete user data (accounts, records, files)
- Generates an audit log entry for the reset action
Implement this as a documented administrative function, not a user-facing feature. Most enterprise customers will never use it — but your ability to demonstrate it exists will matter during CRA conformity assessment.
The September 2026 Deadline: What You Need Ready
CRA enters full application on September 12, 2026 — approximately 15 weeks from the date of this post. Products placed on the EU market after that date must comply with all CRA requirements, including Art.12(2) secure defaults.
For SaaS teams targeting CRA compliance, the minimum viable secure-by-default implementation before September 2026:
Must have (Art.12(2) direct requirements):
- No static or default credentials shipped in any configuration
- MFA available and required-by-default for administrative roles
- TLS 1.2 minimum enforced across all endpoints
- HTTPS redirect with HSTS enabled
- Security event logging for authentication and authorization events
- No plaintext PII or credentials in logs
- Debug endpoints disabled in production
- Configuration reset mechanism documented and tested
Should have (ENISA SbD alignment, expected in conformity assessment):
- Session token expiry enforcement
- CSP enforcement with nonce-based allowlisting
- CORS allowlist (no wildcard)
- API key scope restrictions and expiry
- Automated configuration drift detection in CI/CD
- Log integrity (append-only, rotation with cryptographic chain)
- Third-party webhook signature verification
EU-sovereign hosting alignment (not strictly required but reduces conformity assessment friction):
- TLS termination within EU jurisdiction
- Error tracking and observability data retained in EU
- Log storage in GDPR-compliant EU infrastructure
- Customer data encryption keys customer-managed (not cloud-provider-managed)
What's Next in This Series
This post covered the Secure by Default dimension of ENISA's framework. Post #3 will address Secure Software Development Lifecycle (SDLC) requirements under CRA Art.13 — the process requirements for how you build, test, and update software, not just what you ship.
Post #4 will cover vulnerability disclosure and incident response defaults (CRA Art.14) — the notification timelines, ENISA's coordinated vulnerability disclosure (CVD) framework, and how to implement a compliant responsible disclosure program.
Post #5 will be the series finale: a complete CRA-ENISA Compliance Scorecard you can use to assess your current SaaS product across all five ENISA Secure by Design dimensions.
If you're deploying on EU-sovereign infrastructure — or evaluating whether to migrate before September 2026 — the sota.io EU PaaS guide covers hosting options that reduce your CRA conformity assessment surface.
Summary: CRA Art.12(2) Secure Default Obligations
| Dimension | CRA Requirement | ENISA Minimum | Compliance Status Test |
|---|---|---|---|
| Authentication | Art.12(3)(a) | MFA by default for admin | MFA enrollment rate admin accounts |
| Credentials | Art.12(2) | No static/default credentials | grep scan — zero findings |
| Network exposure | Art.12(3)(c) | TLS enforced, CORS restricted | nmap scan — 443 only |
| Data handling | Art.12(3)(b) | Encryption at rest and transit | No plaintext storage confirmed |
| Logging | Art.13(8) | Security events captured | Auth failure appears in log within 60s |
| Third-party | Art.12(3)(c) | Minimum scope, CSP enforced | CSP header present and strict |
| Configuration reset | Art.12(2) | Reset mechanism documented | Admin can restore secure baseline |
| Drift prevention | Art.12(2) continuous | Automated scanning in CI/CD | CI pipeline fails on config regression |
EU-Native Hosting
Ready to move to EU-sovereign infrastructure?
sota.io is a German-hosted PaaS — no CLOUD Act exposure, no US jurisdiction, full GDPR compliance by design. Deploy your first app in minutes.