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 12:16:07 UTC
(tooling-agents) branch main updated: ASVS audit: 4.2.5.md (redacted)
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 22cbfeb ASVS audit: 4.2.5.md (redacted)
22cbfeb is described below
commit 22cbfeb03eff678354880a3ee0c873cd53700ed0
Author: ASF Tooling Team <ro...@apache.org>
AuthorDate: Tue May 5 14:07:36 2026 +0200
ASVS audit: 4.2.5.md (redacted)
---
ASVS/reports/steve/v3/d0aa7e9/all/4.2.5.md | 204 +++++++++++++++++++++++++++++
1 file changed, 204 insertions(+)
diff --git a/ASVS/reports/steve/v3/d0aa7e9/all/4.2.5.md b/ASVS/reports/steve/v3/d0aa7e9/all/4.2.5.md
new file mode 100644
index 0000000..a84853f
--- /dev/null
+++ b/ASVS/reports/steve/v3/d0aa7e9/all/4.2.5.md
@@ -0,0 +1,204 @@
+# Security Audit Report: ASVS 4.2.5
+
+## Executive Summary
+
+| Field | Value |
+|-------|-------|
+| **Repository** | apache/steve/v3 |
+| **Audit Date** | May 05, 2026 |
+| **Auditor** | Tooling Agents (bundled-pass mode) |
+| **ASVS Requirement** | ASVS 4.2.5 |
+| **Files Analyzed** | 4 relevant / 49 total |
+| **Files Skipped** | 12 |
+
+**Requirement description:** Verify that, if the application (backend or frontend) builds and sends requests, it uses validation, sanitization, or other mechanisms to avoid creating URIs (such as for API calls) or HTTP request header fields (such as Authorization or Cookie), which are too long to be accepted by the receivingβ¦
+
+### Findings Overview
+
+| Severity | Count |
+|----------|-------|
+| π΄ Critical | 0 |
+| π High | 0 |
+| π‘ Medium | 1 |
+| π’ Low | 1 |
+
+---
+
+## ASVS-4.2.5: Prevention of Overly Long URIs and Headers
+
+### Findings for 4.2.5
+
+### [MEDIUM]
+
+**Finding ID:** ASVS-425-MED-001
+
+**Title:** Unbounded user input stored in session flash messages may cause oversized Cookie headers
+
+**File:** `v3/server/pages.py`, lines 424-425, 485-486, 509-510
+
+**Vulnerable Code:**
+
+```python
+# do_create_endpoint (line 424)
+async def do_create_endpoint():
+ form = edict(await quart.request.form)
+ election = steve.election.Election.create(DB_FNAME, form.title, result.uid)
+ # No length validation on form.title
+ await flash_success(f'Created election: {form.title}')
+
+# do_add_issue_endpoint (line 485)
+async def do_add_issue_endpoint(election):
+ form = edict(await quart.request.form)
+ # No length validation on form.title
+ await flash_success(f'Issue "{form.title}" has been added.')
+
+# do_edit_issue_endpoint (line 509)
+async def do_edit_issue_endpoint(election, issue):
+ form = edict(await quart.request.form)
+ # No length validation on form.title
+ await flash_success(f'Issue "{form.title}" has been updated.')
+```
+
+**Data Flow:** User-controlled `form.title` β `quart.flash()` β session storage (cookie) β subsequent requests include oversized `Cookie` header β server rejects request with 431 (Request Header Fields Too Large)
+
+**Proof of Concept:**
+
+```http
+POST /do-create-election HTTP/1.1
+Host: vote.example.org
+Cookie: session=valid_session_token
+Content-Type: application/x-www-form-urlencoded
+
+title=AAAA...AAAA (e.g., 8000+ characters)
+```
+
+After this request is processed, the flash message `'Created election: AAAA...AAAA'` is stored in the session cookie. On the next request, the `Cookie` header may exceed server limits (typically 8KB), causing all subsequent requests from that user to fail with a 431 error until the session/cookie expires. This is a self-inflicted denial of service.
+
+**Impact:** A user (or attacker with the user's session) can permanently lock themselves out of the application by submitting an extremely long title. If session storage uses server-side storage with a small cookie identifier, this is mitigated; however, if using signed/encrypted cookie sessions (common in Flask/Quart), the full flash message content is serialized into the cookie.
+
+**Remediation:**
+
+```python
+MAX_TITLE_LENGTH = 256
+MAX_DESCRIPTION_LENGTH = 4096
+
+@APP.before_request
+async def validate_request_size():
+ """Reject overly large request bodies."""
+ content_length = quart.request.content_length
+ if content_length and content_length > 65536: # 64KB max
+ quart.abort(413, 'Request body too large')
+
+async def do_create_endpoint():
+ form = edict(await quart.request.form)
+ title = form.title[:MAX_TITLE_LENGTH] # Truncate
+ if len(form.title) > MAX_TITLE_LENGTH:
+ await flash_danger(f'Title truncated to {MAX_TITLE_LENGTH} characters.')
+ election = steve.election.Election.create(DB_FNAME, title, result.uid)
+ await flash_success(f'Created election: {title}')
+```
+
+### [LOW]
+
+**Finding ID:** ASVS-425-LOW-001
+
+**Title:** No length validation on vote strings before processing and encryption
+
+**File:** `v3/server/pages.py`, line 384-404; `v3/steve/election.py`, line 231-243
+
+**Vulnerable Code:**
+
+```python
+# pages.py - do_vote_endpoint
+for key, value in form.items():
+ if key.startswith('vote-'):
+ iid = key.split('-', 1)[1]
+ votes[iid] = value # No length validation
+
+# election.py - add_vote
+def add_vote(self, pid: str, iid: str, votestring: str):
+ # No length validation on votestring
+ mayvote = self.q_get_mayvote.first_row(pid, iid)
+ vote_token = crypto.gen_vote_token(md.opened_key, pid, iid, mayvote.salt)
+ ciphertext = crypto.create_vote(vote_token, mayvote.salt, votestring)
+ self.c_add_vote.perform(vote_token, ciphertext)
+```
+
+**Data Flow:** User-controlled form value β `votes[iid]` β `election.add_vote()` β `crypto.create_vote()` β stored as potentially oversized ciphertext in database
+
+**Impact:** An attacker could submit extremely large vote strings that consume excessive memory during encryption and storage. While not directly an HTTP header/URI overflow, the absence of input bounds could lead to resource exhaustion.
+
+**Remediation:**
+
+```python
+MAX_VOTESTRING_LENGTH = 1024 # STV rankings shouldn't exceed this
+
+for iid, votestring in votes.items():
+ if len(votestring) > MAX_VOTESTRING_LENGTH:
+ await flash_danger(f'Vote data too long for issue {iid}.')
+ return quart.redirect(f'/vote-on/{election.eid}', code=303)
+```
+
+### Security Controls Inventory for 4.2.5
+
+| Control | Location | Coverage Status |
+|---------|----------|-----------------|
+| Request body size limit | Not present in application code | **NOT IMPLEMENTED** |
+| Input field length validation (title) | Not present | **NOT IMPLEMENTED** |
+| Input field length validation (description) | Not present | **NOT IMPLEMENTED** |
+| Input field length validation (votestring) | Not present | **NOT IMPLEMENTED** |
+| URI length limit | Not present | Delegated to server |
+| Cookie/header size limit | Not present | Delegated to server |
+| Flash message size bounds | Not present | **NOT IMPLEMENTED** |
+
+### Positive Patterns for 4.2.5
+
+1. **Constrained frontend date inputs**: The JavaScript `saveDate()` function uses HTML `<input type="date">` which constrains the value to ISO date format, limiting the body size of those requests.
+2. **Server-rendered EIDs in URLs**: The template renders `[eid]` directly rather than accepting it from user input for fetch URL construction, preventing client-side URI manipulation.
+3. **Fixed content type headers**: The frontend fetch requests use hardcoded `Content-Type: application/json` rather than user-controllable header values.
+
+---
+
+
+
+## Cross-cutting Architecture Observations
+
+1. **Framework Delegation for HTTP-level Security**: The application relies entirely on Quart/Hypercorn for HTTP protocol handling (message framing, header parsing, Content-Length calculation). While this is appropriate for application code, there is no evidence of explicit server configuration enforcing the HTTP-level security requirements (4.2.1-4.2.4). The security posture depends heavily on the deployment architecture (reverse proxy, ASGI server settings) which is not visible in the [...]
+
+2. **State-Changing GET Requests**: The `/do-open/<eid>` and `/do-close/<eid>` endpoints use GET methods for irreversible state changes. This is particularly concerning in combination with the lack of request smuggling protections (4.2.1), as smuggled GET requests require no body parsing and are easier to exploit.
+
+3. **Placeholder Security Controls**: The CSRF token (`basic.csrf_token = 'placeholder'`) and multiple `### check authz` comments indicate that important security controls are planned but not yet implemented. This creates a false sense of security where templates reference tokens that provide no actual protection.
+
+4. **Sensitive Operations Without Defense-in-Depth**: The voting system handles high-integrity operations (irreversible election state changes, anonymous vote collection) but relies on a single layer of protection (TLS + session cookie authentication). There are no per-message signatures (4.1.5), no request integrity verification beyond transport, and limited input validation for the most critical operations.
+
+5. **Client-Server Trust Boundary**: The frontend JavaScript builds and sends requests to the backend, but there is no server-side validation that these requests are well-formed beyond basic format checks. The absence of size limits, combined with session-stored flash messages, creates a DoS vector (4.2.5).
+
+## Cross-cutting Recommendations
+
+### Immediate (Critical/High Priority)
+
+1. **Implement input length validation** on all user-supplied fields (`title`, `description`, `votestring`) before they are stored or included in flash messages. This prevents the cookie overflow DoS (ASVS-425-MED-001).
+
+2. **Change state-changing operations to POST methods** β convert `/do-open/<eid>` and `/do-close/<eid>` from GET to POST to reduce the attack surface for request smuggling and CSRF.
+
+3. **Implement real CSRF protection** β replace the placeholder token with actual token generation and validation, as this is a prerequisite for meaningful request integrity.
+
+### Short-term (Within Next Sprint)
+
+4. **Add request size limits** at the application level via Quart's `MAX_CONTENT_LENGTH` configuration or middleware, setting appropriate bounds for each endpoint.
+
+5. **Configure ASGI server explicitly** β document and configure Hypercorn (or the deployment ASGI server) settings for:
+ - Maximum header size
+ - HTTP/2 settings frame limits
+ - Connection-specific header rejection in HTTP/2
+
+6. **Add before_request middleware** for HTTP protocol validation (TE/CL conflict detection, CRLF rejection, connection-specific header filtering) as defense-in-depth.
+
+### Long-term (Architecture)
+
+7. **Implement per-message signatures** for critical operations (election open/close, vote submission) using a scheme like HTTP Message Signatures (RFC 9421) or application-level HMAC verification, particularly important if the deployment involves load balancers or TLS-terminating proxies.
+
+8. **Implement server-side session storage** (e.g., Redis-backed) rather than cookie-based sessions to eliminate the cookie size DoS vector entirely and reduce the security impact of session data growth.
+
+9. **Add comprehensive authorization checks** to replace all `### check authz` placeholders, ensuring that election ownership is verified before state-changing operations (currently any committer can open/close any election).
+
\ 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