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/05/05 20:56:07 UTC
(tooling-agents) branch main updated: ASVS audit: 3.5.8.md (redacted) [source: apache/steve/v3 @ d0aa7e9]
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 580e2b7 ASVS audit: 3.5.8.md (redacted) [source: apache/steve/v3 @ d0aa7e9]
580e2b7 is described below
commit 580e2b75f1e722a04fd8c531f1eadfa1b875520e
Author: ASF Tooling Team <ro...@apache.org>
AuthorDate: Tue May 5 22:55:59 2026 +0200
ASVS audit: 3.5.8.md (redacted) [source: apache/steve/v3 @ d0aa7e9]
---
ASVS/reports/steve/v3/d0aa7e9/all/3.5.8.md | 175 +++++++++++++++++++++++++++++
1 file changed, 175 insertions(+)
diff --git a/ASVS/reports/steve/v3/d0aa7e9/all/3.5.8.md b/ASVS/reports/steve/v3/d0aa7e9/all/3.5.8.md
new file mode 100644
index 0000000..287a44f
--- /dev/null
+++ b/ASVS/reports/steve/v3/d0aa7e9/all/3.5.8.md
@@ -0,0 +1,175 @@
+# Security Audit Report: ASVS 3.5.8
+
+## Executive Summary
+
+| Field | Value |
+|-------|-------|
+| **Repository** | apache/steve/v3 |
+| **Audit Date** | May 05, 2026 |
+| **Auditor** | Tooling Agents (bundled-pass mode) |
+| **ASVS Requirement** | ASVS 3.5.8 |
+| **Files Analyzed** | 12 relevant / 49 total |
+| **Files Skipped** | 12 |
+
+**Requirement description:** Verify that authenticated resources (such as images, videos, scripts, and other documents) can be loaded or embedded on behalf of the user only when intended. This can be accomplished by strict validation of the Sec-Fetch-* HTTP request header fields to ensure that the request did not originate…
+
+### Findings Overview
+
+| Severity | Count |
+|----------|-------|
+| 🔴 Critical | 0 |
+| 🟠 High | 1 |
+| 🟡 Medium | 1 |
+| 🟢 Low | 0 |
+
+---
+
+## ASVS-3.5.8: Browser Origin Separation — Cross-Origin Resource Embedding
+
+### Findings for 3.5.8
+
+#### [HIGH]
+**Finding ID:** ASVS-358-HIGH-001
+**Location:** `v3/server/pages.py`, `serve_doc()`, lines 560–574
+**Description:** Authenticated documents are served without `Cross-Origin-Resource-Policy` header or `Sec-Fetch-*` validation, allowing cross-origin embedding.
+
+```python
+@APP.get('/docs/<iid>/<docname>')
+@asfquart.auth.require # fine-grained per-doc authz within the handler
+async def serve_doc(iid, docname):
+ result = await basic_info()
+ db = steve.election.Election.open_database(DB_FNAME)
+ row = db.q_get_mayvote.first_row(result.uid, iid)
+ if not row:
+ quart.abort(404)
+ # No Sec-Fetch-* validation
+ # No Cross-Origin-Resource-Policy header set
+ return await quart.send_from_directory(DOCSDIR / iid, docname)
+```
+
+**Data flow:** Attacker page → `<img src="https://target/docs/IID/secret.pdf">` or `<iframe src="...">` → browser sends session cookie → document returned without CORP → cross-origin page loads authenticated resource
+
+**Proof of Concept:**
+```html
+<!-- Attacker's page on evil.com -->
+<img src="https://steve.example.org/docs/issue123/confidential-candidate-bio.png"
+ onload="alert('Loaded authenticated image cross-origin')">
+<iframe src="https://steve.example.org/docs/issue123/voter-guide.pdf"></iframe>
+```
+
+If the victim is authenticated, the browser sends cookies and the resource loads without restriction.
+
+**Impact:** Authenticated election documents (candidate information, voting guides, confidential ballot materials) could be loaded or embedded by a malicious cross-origin page, leaking sensitive election data or enabling ballot information exfiltration.
+
+**Remediation:**
+```python
+@APP.get('/docs/<iid>/<docname>')
+@asfquart.auth.require
+async def serve_doc(iid, docname):
+ # Validate Sec-Fetch-Site header
+ sec_fetch_site = quart.request.headers.get('Sec-Fetch-Site', '')
+ if sec_fetch_site not in ('same-origin', 'none'):
+ quart.abort(403)
+
+ result = await basic_info()
+ db = steve.election.Election.open_database(DB_FNAME)
+ row = db.q_get_mayvote.first_row(result.uid, iid)
+ if not row:
+ quart.abort(404)
+
+ response = await quart.send_from_directory(DOCSDIR / iid, docname)
+ response.headers['Cross-Origin-Resource-Policy'] = 'same-origin'
+ return response
+```
+
+#### [MEDIUM]
+**Finding ID:** ASVS-358-MED-001
+**Location:** `v3/server/pages.py`, all authenticated page handlers
+**Description:** Authenticated HTML pages (voter dashboard, election management, voting pages) lack `Cross-Origin-Resource-Policy` headers and do not validate `Sec-Fetch-*` headers to prevent cross-origin framing or embedding.
+
+```python
+# Example: vote_on_page serves sensitive election data in HTML
+@APP.get('/vote-on/<eid>')
+@asfquart.auth.require({R.committer})
+@load_election
+@APP.use_template(TEMPLATES / 'vote-on.ezt')
+async def vote_on_page(election):
+ # No Sec-Fetch-Dest or X-Frame-Options validation
+ ...
+```
+
+**Impact:** Authenticated pages containing election data could be framed by malicious sites (clickjacking) or loaded as resources in cross-origin contexts.
+
+**Remediation:**
+```python
+@APP.after_request
+async def add_corp_headers(response):
+ # For authenticated responses, restrict cross-origin loading
+ response.headers['Cross-Origin-Resource-Policy'] = 'same-origin'
+ response.headers['X-Frame-Options'] = 'DENY'
+ return response
+```
+
+### Security Controls Inventory for 3.5.8
+
+| Control | Location | Status |
+|---------|----------|--------|
+| `Sec-Fetch-Site` validation | Not found anywhere | ❌ Missing |
+| `Sec-Fetch-Dest` validation | Not found anywhere | ❌ Missing |
+| `Cross-Origin-Resource-Policy` header | Not set on any response | ❌ Missing |
+| `X-Frame-Options` header | Not found | ❌ Missing |
+| Authentication gate on `/docs/` | `serve_doc()` line 567 | ✅ Applied |
+| Authorization check on `/docs/` | `q_get_mayvote` check, line 567 | ✅ Applied |
+
+### Positive Patterns for 3.5.8
+
+1. **Per-document authorization**: `serve_doc()` verifies the authenticated user has a `mayvote` entry for the specific issue before serving the document.
+2. **Authentication required on sensitive pages**: All election-related pages require `R.committer` authentication.
+
+---
+
+
+
+## Cross-cutting Architecture Observations
+
+1. **Missing Security Header Middleware**: The application lacks a centralized response header middleware to set security headers (`X-Content-Type-Options`, `Cross-Origin-Resource-Policy`, `X-Frame-Options`, `Content-Security-Policy`). This creates Type B gaps—where controls should exist application-wide but don't.
+
+2. **Self-Hosting Pattern (Positive)**: The architecture decision to self-host all third-party assets via `fetch-thirdparty.sh` with version pinning eliminates CDN compromise risks and makes SRI defense-in-depth rather than critical. This is a strong architectural decision for a voting application.
+
+3. **Authentication Framework Dependency**: The application delegates authentication and redirect handling to the `asfquart` framework, creating an audit boundary. The security of redirect validation (3.7.2) depends entirely on the framework's implementation of `/auth` endpoints.
+
+4. **Inline JavaScript Pattern**: The application embeds authorized data in inline `<script>` blocks within HTML pages rather than as separate authenticated JavaScript resources. This inherently prevents XSSI attacks (3.5.7) through the Same-Origin Policy applied to HTML responses.
+
+5. **Document Serving Without Resource Policy**: The `serve_doc` endpoint correctly implements authentication and authorization but lacks modern browser-side protections (CORP, Sec-Fetch validation), creating a false sense of security—the authorization check alone doesn't prevent cross-origin resource embedding by an already-authenticated user's browser (Type B gap).
+
+6. **Template Security**: EZT templates use `[format "js,html"]` escaping for user-generated content injected into JavaScript contexts, showing awareness of XSS prevention, which indirectly supports browser origin separation requirements.
+
+## Cross-cutting Recommendations
+
+### Immediate (Critical/High Priority)
+1. **Add `Cross-Origin-Resource-Policy: same-origin` to authenticated responses**, particularly `serve_doc()`. This is a single-header addition that prevents the most impactful cross-origin resource theft scenario (ASVS-358-HIGH-001).
+
+2. **Implement Sec-Fetch validation middleware** for all authenticated endpoints:
+ ```python
+ @APP.before_request
+ async def validate_sec_fetch():
+ if quart.request.path.startswith('/docs/') or quart.request.path.startswith('/do-'):
+ sec_fetch_site = quart.request.headers.get('Sec-Fetch-Site', '')
+ if sec_fetch_site not in ('same-origin', 'none', ''):
+ quart.abort(403)
+ ```
+
+### Short-term (Medium Priority)
+3. **Add centralized security headers middleware** to set `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, and `Cross-Origin-Resource-Policy` on all responses.
+
+4. **Self-host the Apache feather SVG** to eliminate the last external resource dependency and achieve full resource isolation.
+
+5. **Verify `/auth` endpoint redirect validation** in the `asfquart` framework—confirm that `login=` and `logout=` parameters are validated against an allowlist or restricted to same-origin paths.
+
+### Long-term (Low Priority / Defense-in-Depth)
+6. **Add SRI to `bootstrap-icons.css`** for consistency with other third-party assets.
+
+7. **Implement external link interstitial** for ASVS L3 compliance—either a JavaScript confirmation dialog or a dedicated redirect page for the small number of external links.
+
+8. **Add `rel="noopener noreferrer"` to external links** to prevent reverse tabnapping via the `target` attribute on the Privacy Policy link.
+
\ 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