You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tooling.apache.org by as...@apache.org on 2026/04/21 19:14:21 UTC

(tooling-agents) branch main updated: ASVS L3 audit: 12.2.2 (tls_and_transport_security)

This is an automated email from the ASF dual-hosted git repository.

asf-tooling pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-agents.git


The following commit(s) were added to refs/heads/main by this push:
     new 6dc3bac  ASVS L3 audit: 12.2.2 (tls_and_transport_security)
6dc3bac is described below

commit 6dc3bac18adb84ffbc23b29fbb18aa9788eae586
Author: ASF Tooling Team <ro...@apache.org>
AuthorDate: Tue Apr 21 21:14:16 2026 +0200

    ASVS L3 audit: 12.2.2 (tls_and_transport_security)
---
 .../d0aa7e9/tls_and_transport_security/12.2.2.md   | 262 +++++++++++++++++++++
 1 file changed, 262 insertions(+)

diff --git a/repos/apache/ASVS/reports/steve/v3/d0aa7e9/tls_and_transport_security/12.2.2.md b/repos/apache/ASVS/reports/steve/v3/d0aa7e9/tls_and_transport_security/12.2.2.md
new file mode 100644
index 0000000..adab6ae
--- /dev/null
+++ b/repos/apache/ASVS/reports/steve/v3/d0aa7e9/tls_and_transport_security/12.2.2.md
@@ -0,0 +1,262 @@
+# ASVS 12.2.2 Security Audit Report: Publicly Trusted TLS Certificates
+
+## Executive Summary
+
+**Repository:** apache/steve
+
+**Audit Date:** Apr 21, 2026
+
+**Auditor:** Tooling Agents
+
+**ASVS Requirement:** 12.2.2 — ASVS Requirement 12.2.2  
+Description: Verify that external facing services use publicly trusted TLS certificates.  
+Level: 1  
+Section: HTTPS Communication with External Facing Services  
+Section Description: Ensure all HTTP traffic to external-facing services which the application exposes is sent encrypted, with publicly trusted certificates.  
+Chapter: Secure Communication  
+Control Objective: This chapter includes requirements related to the specific mechanisms that should be in place to protect data in transit, both between an end-user client and a backend service, as well as between internal and backend services.
+
+**Files analyzed:** 2 relevant out of 2 total, 0 skipped
+
+**Finding Counts:**
+
+| Severity | Count |
+|----------|-------|
+| Critical | 1 |
+| High | 0 |
+| Medium | 0 |
+| Low | 0 |
+| **Total** | **1** |
+
+**Summary:** The audit evaluates whether external-facing services use publicly trusted TLS certificates. Analysis of the server bootstrap code and configuration template reveals that TLS is entirely optional with no enforcement mechanism, and the only provided configuration guidance references development-only (mkcert) certificates that are not publicly trusted.
+
+---
+
+## Security Controls Inventory
+
+| Control | Location | Status | Coverage |
+|---------|----------|--------|----------|
+| TLS certificate loading | `main.py:87-90` | DEFINED | Standalone mode only |
+| TLS enforcement (must-use) | N/A | **MISSING** | No entry points covered |
+| Certificate trust validation | N/A | **MISSING** | No entry points covered |
+| TLS minimum version enforcement | N/A | **MISSING** | No entry points covered |
+| Cipher suite restriction | N/A | **MISSING** | No entry points covered |
+| ASGI/Hypercorn TLS config | `main.py:97-117` | **MISSING** | Not addressed |
+
+---
+
+## Critical File Review
+
+| File | Security Relevance | Key Concern |
+|------|-------------------|-------------|
+| `main.py` | TLS configuration and server startup | TLS optional, no version/cipher enforcement, no certificate validation |
+| `config.yaml.example` | Only TLS configuration template | References mkcert dev certificates, documents plain HTTP as acceptable |
+| `certs/` directory | Certificate storage | Contains development certificates by default |
+
+**Key Security-Sensitive Functions Reviewed:**
+
+| File | Function | Lines | Purpose | Security Assessment |
+|------|----------|-------|---------|---------------------|
+| `main.py` | `run_standalone()` | 87-91 | TLS certificate configuration | Optional TLS, no validation |
+| `main.py` | `run_asgi()` | 97-117 | ASGI server mode | No TLS configuration |
+| `config.yaml.example` | N/A (config) | 31-33 | Certificate path specification | References mkcert dev certificates |
+
+---
+
+## Findings
+
+### Critical Severity
+
+#### ASVS-1222-SEV-001 — TLS Not Enforced and No Certificate Trust Validation (Type B Gap)
+
+**Severity:** CRITICAL
+
+**Location:** 
+- File: `v3/server/main.py`
+- Function: `run_standalone()`
+- Lines: 87–91
+- Related file: `v3/server/config.yaml.example`, lines 31–33
+
+**Related Functions Checked:**
+- `run_standalone()` — TLS configuration in standalone mode
+- `run_asgi()` — ASGI deployment mode (no TLS configuration)
+- `create_app()` — Application initialization
+
+**Description:**
+
+The TLS control *exists* (certificate paths can be configured) but is *never enforced*. The conditional check `if app.cfg.server.certfile:` means TLS is silently skipped when the configuration field is empty, allowing the voting application to serve all external endpoints—including authentication, vote submission, and election management—over plain HTTP. Additionally, when TLS is enabled, no validation occurs to ensure the provided certificate is publicly trusted, and no TLS protocol ver [...]
+
+The only configuration template provided references mkcert-generated development certificates.
+
+**Gap Classification:** Type B — The TLS capability is *defined* (certificate paths are loadable) but *not enforced* (no mandatory check, no trust validation, no version pinning). This creates false confidence that TLS is "supported" while allowing completely insecure deployment.
+
+**Vulnerable Code:**
+
+`main.py:87-91`:
+```python
+if app.cfg.server.certfile:
+    kwargs['certfile'] = CERTS_DIR / app.cfg.server.certfile
+    kwargs['keyfile'] = CERTS_DIR / app.cfg.server.keyfile
+    extra_files.update((kwargs['certfile'], kwargs['keyfile']))
+
+# Spool up the app!
+app.runx(port=app.cfg.server.port, extra_files=extra_files, **kwargs)
+```
+
+`config.yaml.example:30-33`:
+```yaml
+certfile: localhost.apache.org+3.pem
+keyfile: localhost.apache.org+3-key.pem
+```
+
+The filename pattern `localhost.apache.org+3.pem` is characteristic of [mkcert](https://github.com/FiloSottile/mkcert), which generates certificates signed by a local-only CA that is **not publicly trusted**. These certificates will fail trust validation on any client that hasn't installed mkcert's root CA.
+
+In ASGI mode (`run_asgi()`), TLS configuration is entirely absent from the application:
+
+```python
+def run_asgi():
+    ...
+    global steve_app
+    steve_app = create_app()
+    # No TLS configuration whatsoever
+```
+
+**Data Flow:**
+```
+External voter/admin client
+  → HTTP (port 58383, no TLS enforced)
+    → Authentication tokens, encrypted votes, election data transmitted in cleartext
+      → Missing control: no enforcement of TLS enablement
+      → Missing control: no validation that certificate is publicly trusted
+      → Missing control: no TLS 1.2+ minimum version
+```
+
+**Proof of Concept:**
+
+1. Copy `config.yaml.example` to `config.yaml`
+2. Clear the `certfile` and `keyfile` fields:
+   ```yaml
+   certfile:
+   keyfile:
+   ```
+3. Start the server: `./main.py`
+4. Server starts on plain HTTP — all voting endpoints serve unencrypted traffic
+5. Alternatively, leave the mkcert certificates in place — server starts with TLS but clients receive certificate warnings as the certificate is not publicly trusted
+
+**Impact:**
+- **Plain HTTP deployment**: All authentication tokens (OAuth), session cookies, encrypted votes, and election management data transmitted in cleartext. Enables passive eavesdropping and active man-in-the-middle attacks against voter sessions.
+- **mkcert certificate deployment**: Clients must bypass certificate warnings. Users trained to accept invalid certificates are vulnerable to MITM with attacker-controlled certificates. Automated clients may fail or require `verify=False`.
+- **ASGI deployment**: No TLS guidance or enforcement from the application; entirely dependent on external operator configuration with no validation.
+
+**Remediation:**
+
+```python
+# main.py - Enforce TLS in standalone mode
+import ssl
+
+def run_standalone():
+    ...
+    app = create_app()
+    
+    kwargs = {}
+    certfile = app.cfg.server.get('certfile')
+    keyfile = app.cfg.server.get('keyfile')
+    
+    if not certfile or not keyfile:
+        _LOGGER.critical(
+            "TLS certificates not configured. External-facing services "
+            "MUST use TLS. Set server.certfile and server.keyfile in config.yaml."
+        )
+        sys.exit(1)
+    
+    cert_path = CERTS_DIR / certfile
+    key_path = CERTS_DIR / keyfile
+    
+    # Validate certificate exists and is not a development/self-signed cert
+    if not cert_path.exists() or not key_path.exists():
+        _LOGGER.critical("Certificate files not found: %s, %s", cert_path, key_path)
+        sys.exit(1)
+    
+    kwargs['certfile'] = cert_path
+    kwargs['keyfile'] = key_path
+    
+    # Enforce minimum TLS version
+    ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+    ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
+    ssl_context.load_cert_chain(certfile=cert_path, keyfile=key_path)
+    
+    app.runx(port=app.cfg.server.port, extra_files=extra_files, **kwargs)
+```
+
+Update the configuration template to reference publicly trusted certificates:
+
+```yaml
+# config.yaml.example
+server:
+    # TLS is REQUIRED. Obtain certificates from a public CA (e.g., Let's Encrypt).
+    # Do NOT use self-signed or mkcert certificates in production.
+    certfile: /etc/letsencrypt/live/vote.apache.org/fullchain.pem
+    keyfile: /etc/letsencrypt/live/vote.apache.org/privkey.pem
+```
+
+---
+
+## Positive Security Patterns
+
+| Pattern | Location | Assessment |
+|---------|----------|------------|
+| OAuth over HTTPS | `main.py:41-44` | OAuth endpoints use `https://` URLs correctly |
+| Certificate path resolution | `main.py:29-30` | Uses `pathlib.resolve()` to prevent path confusion |
+| Separate certs directory | `main.py:30` | Certificates isolated in dedicated directory |
+| Configuration-driven TLS | `config.yaml.example:31-33` | TLS parameters externalized from code (good for rotation) |
+
+---
+
+## Architecture Observations
+
+1. **Proxy architecture acknowledged but not enforced**: The config comment states "a proxy sits in front of this server," suggesting TLS termination at a reverse proxy. However, this is neither documented as a requirement nor validated by the application. An operator could deploy the server directly exposed to the internet without a proxy.
+
+2. **Two deployment modes, neither enforces TLS**: Standalone mode makes TLS optional via config. ASGI mode delegates TLS entirely to the external server (Hypercorn). Neither mode includes any check that TLS is actually in effect for external-facing traffic.
+
+3. **No HSTS enforcement visible**: No Strict-Transport-Security headers observed in the server bootstrap. While these might exist in the `pages` or `api` modules (not provided), their absence from the main server configuration is notable.
+
+---
+
+## Recommendations Summary
+
+### Immediate Actions (Critical Priority)
+
+1. **Enforce TLS as mandatory** — Remove the option to run plain HTTP in production. If a proxy architecture is intended, document it as a deployment requirement and add a configuration flag (e.g., `behind_proxy: true`) that explicitly acknowledges this choice.
+
+2. **Update configuration template** — Replace mkcert certificate references with guidance for publicly trusted certificates (Let's Encrypt, organizational CA) and add comments warning against development certificates in production.
+
+3. **Enforce TLS 1.2 minimum** — When TLS is enabled in standalone mode, configure an `ssl.SSLContext` with `minimum_version = TLSVersion.TLSv1_2` and restrict cipher suites to modern, secure options.
+
+### Short-term Actions
+
+4. **Add certificate validation** — Implement checks to verify certificates are not self-signed or development certificates before server startup.
+
+5. **Document proxy deployment requirements** — If TLS termination at a reverse proxy is the intended architecture, create explicit deployment documentation and configuration validation.
+
+### Long-term Actions
+
+6. **Implement HSTS headers** — Add Strict-Transport-Security headers to enforce HTTPS at the application level.
+
+7. **Add certificate monitoring** — Implement certificate expiration monitoring and alerting to prevent service disruption.
+
+---
+
+## Appendix: Files Analyzed
+
+<details>
+<summary>Click to expand full file list (2 files)</summary>
+
+1. `v3/server/config.yaml.example` (relevance: 10/10)
+   - Configuration template for TLS certificates
+   - Contains mkcert development certificate references
+
+2. `v3/server/main.py` (relevance: 10/10)
+   - Server bootstrap and TLS configuration
+   - Contains `run_standalone()` and `run_asgi()` functions
+
+</details>
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org