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/22 15:21:15 UTC
(tooling-agents) branch main updated: ASVS L3 audit: 7.1.3 (ch07_general)
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 3d894fd ASVS L3 audit: 7.1.3 (ch07_general)
3d894fd is described below
commit 3d894fd2afc3bbeaf61167cb152c6b2d45de0010
Author: ASF Tooling Team <ro...@apache.org>
AuthorDate: Wed Apr 22 17:21:09 2026 +0200
ASVS L3 audit: 7.1.3 (ch07_general)
---
.../reports/steve/v3/d0aa7e9/ch07_general/7.1.3.md | 445 +++++++++++++++++++++
1 file changed, 445 insertions(+)
diff --git a/repos/apache/ASVS/reports/steve/v3/d0aa7e9/ch07_general/7.1.3.md b/repos/apache/ASVS/reports/steve/v3/d0aa7e9/ch07_general/7.1.3.md
new file mode 100644
index 0000000..9306afe
--- /dev/null
+++ b/repos/apache/ASVS/reports/steve/v3/d0aa7e9/ch07_general/7.1.3.md
@@ -0,0 +1,445 @@
+# ASVS 7.1.3 Audit Report: Session Management Documentation for Federated Identity
+
+## Executive Summary
+
+- **Repository:** apache/steve
+- **Audit Date:** Apr 22, 2026
+- **Auditor:** Tooling Agents
+- **ASVS Requirement:** 7.1.3 — Verify that all systems that create and manage user sessions as part of a federated identity management ecosystem (such as SSO systems) are documented along with controls to coordinate session lifetimes, termination, and any other conditions that require re-authentication.
+- **Files Analyzed:** 4 relevant out of 49 total, 12 skipped
+
+### Finding Counts
+
+| Severity | Count |
+|----------|-------|
+| Critical | 0 |
+| High | 1 |
+| Medium | 2 |
+| Low | 0 |
+| **Total** | **3** |
+
+### Summary
+
+The application integrates with an ASF (Apache Software Foundation) federated SSO system via `asfquart.session` and `asfquart.auth`, but critically lacks session termination controls, session lifetime coordination, re-authentication triggers for sensitive operations, and any documentation of these session management decisions. This directly violates ASVS 7.1.3.
+
+---
+
+## Security Controls Inventory
+
+| Control | Location | Status | Coverage |
+|---------|----------|--------|----------|
+| SSO Session Reading | `pages.py:74` (`basic_info()`) | ✅ Implemented | All authenticated routes |
+| Auth Requirement (committer) | `@asfquart.auth.require({R.committer})` | ✅ Implemented | Most admin/voting routes |
+| Auth Requirement (PMC) | `@asfquart.auth.require({R.pmc_member})` | ✅ Implemented | `do_create_endpoint` only |
+| Auth Requirement (any session) | `@asfquart.auth.require` | ✅ Implemented | profile, settings, serve_doc |
+| Session Termination / Logout | — | ❌ **Missing entirely** | 0 routes |
+| Session Lifetime Configuration | — | ❌ **Missing entirely** | No code or config |
+| Session Freshness / Re-auth | — | ❌ **Missing entirely** | 0 sensitive operations |
+| CSRF Token | `pages.py:88` | ⚠️ Placeholder only | Acknowledged debt |
+| Session Management Documentation | — | ❌ **Missing entirely** | No docs provided |
+
+---
+
+## Critical File Review
+
+### `v3/server/pages.py`
+
+| Line(s) | Element | Risk | Finding |
+|---------|---------|------|---------|
+| 74–89 | `basic_info()` | Session read with no lifetime/freshness validation | ASVS-713-SEV-002 |
+| All routes | Route definitions | No logout endpoint anywhere | ASVS-713-SEV-001 |
+| 387, 432, 455, 475, 497, 520, 544 | `### check authz` | Planned but unimplemented authorization/re-auth | ASVS-713-SEV-003 |
+| 449–466 | `do_open_endpoint` | GET + no re-auth for irreversible operation | ASVS-713-SEV-003 |
+| 470–485 | `do_close_endpoint` | GET + no re-auth for irreversible operation | ASVS-713-SEV-003 |
+
+### `v3/steve/election.py`
+
+| Line(s) | Element | Risk | Notes |
+|---------|---------|------|-------|
+| N/A | Election management logic | No session-related security concerns | Proper use of transactions and parameterized queries |
+
+### `v3/steve/crypto.py`
+
+| Line(s) | Element | Risk | Notes |
+|---------|---------|------|-------|
+| N/A | Cryptographic primitives | No session-related security concerns | Strong CSPRNG usage throughout |
+
+### `v3/docs/schema.md`
+
+| Section | Risk | Finding |
+|---------|------|---------|
+| Entire document | No session management documentation | Supports all findings |
+| "Election Lifecycle" section | Documents data states but not session states | ASVS-713-SEV-002 |
+
+---
+
+## Findings
+
+### HIGH Severity
+
+#### ASVS-713-HIGH-001: Absence of Session Termination Control in SSO-Integrated Voting Application
+
+**Severity:** HIGH
+
+**Location:** `v3/server/pages.py` (entire file — routes inventory)
+
+**Related Functions Checked:**
+- All route definitions in `pages.py`
+- `asfquart.session.read()` usage
+- `asfquart.auth.require` decorator usage
+
+**Description:**
+
+The application is integrated with the ASF federated SSO ecosystem through `asfquart.session` and `asfquart.auth`, but provides no session termination (logout) endpoint. An exhaustive review of all defined routes confirms no logout mechanism exists:
+
+**Vulnerable Code:**
+
+```python
+# All defined routes in pages.py - NO logout route present:
+# GET / — home_page
+# GET /voter — voter_page
+# GET /vote-on/<eid> — vote_on_page
+# POST /do-vote/<eid> — do_vote_endpoint
+# GET /admin — admin_page
+# GET /manage/<eid> — manage_page
+# GET /manage-stv/<eid>/<iid> — manage_stv_page
+# POST /do-set-open_at/<eid> — do_set_open_at_endpoint
+# POST /do-set-close_at/<eid> — do_set_close_at_endpoint
+# POST /do-create-election — do_create_endpoint
+# GET /do-open/<eid> — do_open_endpoint
+# GET /do-close/<eid> — do_close_endpoint
+# POST /do-add-issue/<eid> — do_add_issue_endpoint
+# POST /do-edit-issue/<eid>/<iid> — do_edit_issue_endpoint
+# POST /do-delete-issue/<eid>/<iid> — do_delete_issue_endpoint
+# GET /profile — profile_page
+# GET /settings — settings_page
+# GET /about — about_page
+# GET /docs/<iid>/<docname> — serve_doc
+# GET /static/<path:filename> — serve_static
+# GET /favicon.ico — serve_favicon
+# *** NO /logout or /do-logout ***
+```
+
+**Data Flow:**
+
+```
+SSO Provider → asfquart.session.read() creates session → Application uses session indefinitely → **No termination path**
+```
+
+**Impact:**
+
+- Users cannot terminate their voting session after casting votes, leaving sessions open indefinitely on shared/public computers.
+- If the SSO provider terminates the IdP session, there is no evidence the application-layer session is also invalidated (no coordination code exists).
+- In a voting system, persistent sessions create an extended window for session hijacking that could lead to unauthorized vote casting.
+
+**Proof of Concept:**
+
+1. User authenticates via ASF SSO and casts a vote
+2. User walks away from shared workstation
+3. No logout button or mechanism exists to end the session
+4. Another person uses the same browser and can access `/voter`, `/admin`, and cast votes as the previous user
+
+**Remediation:**
+
+```python
+@APP.get('/logout')
+@asfquart.auth.require
+async def logout_endpoint():
+ """Terminate the local session and redirect to SSO logout."""
+ # Destroy the application-side session
+ await asfquart.session.destroy()
+
+ _LOGGER.info(f'User session terminated')
+
+ # Redirect to the SSO provider's logout endpoint for coordinated termination
+ sso_logout_url = APP.cfg.get('sso_logout_url', '/')
+ return quart.redirect(sso_logout_url, code=303)
+```
+
+---
+
+### MEDIUM Severity
+
+#### ASVS-713-MEDIUM-002: No Session Lifetime Coordination with Federated SSO Provider
+
+**Severity:** MEDIUM
+
+**Location:** `v3/server/pages.py`, lines 71–89 (`basic_info()`)
+
+**Related Functions Checked:**
+- `basic_info()` — sole session-reading function
+- `asfquart.session.read()` — SSO session consumption
+- Configuration files and environment variables (none found)
+- `schema.md` documentation (no session management content)
+
+**Description:**
+
+The application reads sessions from the federated SSO provider but implements no controls to coordinate session lifetimes. The `basic_info()` function — the sole session-reading code — performs a binary check (session exists or not) with no validation of session age, expiry, or freshness.
+
+**Vulnerable Code:**
+
+```python
+async def basic_info():
+ """Return base-level EZT template data."""
+ basic = edict()
+ # ... flash messages ...
+
+ s = await asfquart.session.read() # Line 74: Binary read, no lifetime check
+ if s:
+ basic.update(
+ uid=s['uid'],
+ name=s['fullname'],
+ email=s['email'],
+ # NOTE: No session creation timestamp checked
+ # NOTE: No session last-activity timestamp checked
+ # NOTE: No session expiry validation
+ # NOTE: No SSO token expiry coordination
+ )
+ else:
+ basic.update(uid=None, name=None, email=None)
+
+ ### generate a real token and store in the session
+ basic.csrf_token = 'placeholder' # Line 88: Also confirms no session writes
+
+ return basic
+```
+
+**Data Flow:**
+
+```
+SSO Provider issues token (unknown lifetime) → asfquart.session.read() → Application accepts unconditionally → No freshness validation → No idle timeout → No absolute timeout
+```
+
+**Impact:**
+
+- If the SSO provider issues long-lived tokens, the voting application will honor them indefinitely, even for an election that opened and closed during that period.
+- No idle timeout means abandoned sessions remain valid, widening the attack window.
+- ASVS 7.1.3 explicitly requires documentation of "controls to coordinate session lifetimes" — none exists.
+
+**Proof of Concept:**
+
+1. User authenticates and receives SSO session
+2. User leaves browser open for hours/days
+3. Session remains valid with no timeout enforcement
+4. Session can be exploited at any point during this extended window
+
+**Remediation:**
+
+```python
+# In configuration:
+SESSION_MAX_AGE = 3600 # 1 hour absolute timeout
+SESSION_IDLE_TIMEOUT = 1800 # 30 minutes idle timeout
+
+async def basic_info():
+ basic = edict()
+ basic.flashes = [...]
+
+ s = await asfquart.session.read()
+ if s:
+ # Validate session freshness
+ now = datetime.datetime.now().timestamp()
+ created_at = s.get('created_at', 0)
+ last_activity = s.get('last_activity', 0)
+
+ if (now - created_at) > SESSION_MAX_AGE:
+ await asfquart.session.destroy()
+ s = None # Force re-authentication
+ elif (now - last_activity) > SESSION_IDLE_TIMEOUT:
+ await asfquart.session.destroy()
+ s = None # Force re-authentication
+ else:
+ # Update last activity
+ s['last_activity'] = now
+ await asfquart.session.write(s)
+ # ... rest of function
+```
+
+Additionally, create a session management documentation file (e.g., `docs/session-management.md`) covering:
+- SSO provider identity and integration points
+- Session lifetime policy and rationale
+- Idle timeout configuration
+- Termination coordination between the app and SSO provider
+- Re-authentication conditions
+
+---
+
+#### ASVS-713-MEDIUM-003: No Re-authentication Requirements for Critical Election Operations
+
+**Severity:** MEDIUM
+
+**Location:** `v3/server/pages.py` — multiple endpoints
+
+**Related Functions Checked:**
+- `do_vote_endpoint` (line 382)
+- `do_open_endpoint` (line 449)
+- `do_close_endpoint` (line 470)
+- `do_create_endpoint` (line 427)
+- `do_delete_issue_endpoint` (line 539)
+- `do_add_issue_endpoint`
+- `do_edit_issue_endpoint`
+- `### check authz` placeholders (lines 387, 432, 455, 475, 497, 520, 544)
+
+**Description:**
+
+Critical, irreversible operations in the election lifecycle rely solely on the initial SSO authentication with no session freshness check or re-authentication requirement. The `### check authz` comments throughout the code confirm these checks were planned but never implemented.
+
+**Affected Endpoints:**
+
+| Endpoint | Operation | Impact | Re-auth Required? |
+|----------|-----------|--------|--------------------|
+| `POST /do-vote/<eid>` (line 382) | Cast votes | Vote manipulation | ❌ No |
+| `GET /do-open/<eid>` (line 449) | Open election | Premature election opening | ❌ No |
+| `GET /do-close/<eid>` (line 470) | Close election | Premature election closure | ❌ No |
+| `POST /do-create-election` (line 427) | Create election | Unauthorized election creation | ❌ No |
+| `POST /do-delete-issue/<eid>/<iid>` (line 539) | Delete issue | Data destruction | ❌ No |
+
+**Vulnerable Code:**
+
+```python
+@APP.post('/do-vote/<eid>')
+@asfquart.auth.require({R.committer}) # Only checks SSO session exists
+@load_election
+async def do_vote_endpoint(election):
+ result = await basic_info()
+ ### check authz # ← NEVER IMPLEMENTED (line 387)
+
+ # ... immediately processes votes with no session freshness check
+ form = edict(await quart.request.form)
+ for iid, votestring in votes.items():
+ election.add_vote(result.uid, iid, votestring) # Irreversible
+```
+
+**Data Flow:**
+
+```
+SSO session (possibly hours/days old) → @asfquart.auth.require (binary check) → ### check authz (NOT IMPLEMENTED) → Sensitive operation executes immediately
+```
+
+**Impact:**
+
+- A session hijacked hours ago can be used to cast votes, open/close elections, and delete issues without any freshness verification.
+- ASVS 7.1.3 requires documented "conditions that require re-authentication" — none are defined or enforced.
+- The `do_open_endpoint` and `do_close_endpoint` use **GET** requests for irreversible state changes, meaning a stale session combined with a crafted link could trigger these operations.
+
+**Proof of Concept:**
+
+1. Attacker obtains valid session token (e.g., XSS, network sniffing, shared computer)
+2. Hours/days pass with no session invalidation
+3. Attacker uses stale session to:
+ - Cast votes as the victim
+ - Open/close elections prematurely
+ - Delete election issues
+4. No re-authentication challenge occurs
+
+**Remediation:**
+
+```python
+import time
+
+REAUTH_THRESHOLD = 300 # 5 minutes for critical operations
+
+async def require_fresh_session():
+ """Verify the session was recently authenticated for sensitive operations."""
+ s = await asfquart.session.read()
+ if not s:
+ quart.abort(401)
+
+ last_auth = s.get('last_authenticated_at', 0)
+ if (time.time() - last_auth) > REAUTH_THRESHOLD:
+ # Store the intended destination and redirect to re-auth
+ s['return_to'] = quart.request.url
+ await asfquart.session.write(s)
+ return quart.redirect('/reauth', code=303)
+ return None
+
+@APP.post('/do-vote/<eid>')
+@asfquart.auth.require({R.committer})
+@load_election
+async def do_vote_endpoint(election):
+ reauth_redirect = await require_fresh_session()
+ if reauth_redirect:
+ return reauth_redirect
+ # ... proceed with voting
+```
+
+Additionally:
+- Convert `do_open_endpoint` and `do_close_endpoint` from GET to POST
+- Implement all `### check authz` placeholders with proper authorization logic
+- Document re-authentication requirements in session management documentation
+
+---
+
+## Positive Security Patterns
+
+| Pattern | Location | Assessment |
+|---------|----------|------------|
+| Strong cryptographic primitives | `crypto.py` — Argon2, HKDF-SHA256, BLAKE2b | Well-designed key derivation chain |
+| CSPRNG for all random values | `crypto.py` — `secrets.token_bytes()`, `secrets.randbelow()` | Correct use throughout |
+| Parameterized SQL queries | `election.py` — via `asfpy.db` | Prevents SQL injection |
+| Non-predictable election/issue IDs | `crypto.py:create_id()` — 10-char hex | Prevents enumeration |
+| Per-voter cryptographic salts | `election.py:add_salts()` | Strong voter anonymity |
+| Transactional integrity | `election.py` — `BEGIN TRANSACTION`/`COMMIT` | Consistent state during critical operations |
+| Sensitive metadata exclusion | `election.py:get_metadata()` vs `_all_metadata()` | Salt and opened_key never exposed via public API |
+| Comprehensive security event logging | `pages.py` — all state-changing operations | Auditable trail with user/election/issue IDs |
+| Vote eligibility verification | `pages.py:vote_on_page()` line 246 | Checks `q_find_issues` before showing ballot |
+| Election state machine enforcement | `election.py` — `assert self.is_editable()` etc. | Prevents operations in wrong state |
+
+---
+
+## Architecture Observations
+
+1. **Federated Identity Dependency**: The entire authentication system is delegated to `asfquart.session` and `asfquart.auth`. While this centralizes identity management (good), the voting application has zero visibility into or control over session lifecycle events from the SSO provider.
+
+2. **Session as Opaque Blob**: The session is treated as a read-only dictionary (`s['uid']`, `s['fullname']`, `s['email']`). The application never writes to the session (note the placeholder CSRF token at line 88). This means the application cannot track session metadata like creation time, last activity, or local session state.
+
+3. **Authorization Debt**: The pervasive `### check authz` comments (appearing in `load_election`, `load_election_issue`, `do_vote_endpoint`, `do_create_endpoint`, `do_open_endpoint`, `do_close_endpoint`, `do_add_issue_endpoint`, `do_edit_issue_endpoint`, `do_delete_issue_endpoint`) indicate that fine-grained authorization was planned as part of the session/identity management design but remains unimplemented. This represents a systemic gap that compounds the session management issues.
+
+4. **Missing Session Documentation**: The `schema.md` provides thorough documentation of the database schema and election lifecycle but contains no mention of session management, SSO integration architecture, session lifetime policies, or re-authentication requirements — all explicitly required by ASVS 7.1.3.
+
+---
+
+## Recommendations Summary
+
+### Immediate Actions (Priority 1)
+
+| Action | Addresses | Effort |
+|--------|-----------|--------|
+| **Implement session termination (logout) endpoint** with SSO provider logout coordination | ASVS-713-HIGH-001 | Low |
+| **Create session management documentation** covering SSO integration, session lifetime policy, termination coordination, and re-authentication conditions | All findings (ASVS 7.1.3 core requirement) | Medium |
+
+### Short-term Actions (Priority 2)
+
+| Action | Addresses | Effort |
+|--------|-----------|--------|
+| **Implement session lifetime controls** (absolute timeout, idle timeout) coordinated with the ASF SSO provider's session policy | ASVS-713-MEDIUM-002 | Medium |
+| **Implement re-authentication for sensitive operations** (voting, election open/close, election creation, issue deletion) | ASVS-713-MEDIUM-003 | Medium |
+
+### Long-term Actions (Priority 3)
+
+| Action | Addresses | Effort |
+|--------|-----------|--------|
+| **Complete all `### check authz` placeholders** with fine-grained authorization that verifies the authenticated user is the election owner or has appropriate `authz` group membership | ASVS-713-MEDIUM-003 | High |
+| **Convert `do_open` and `do_close` from GET to POST** to prevent state changes via link prefetching and reduce session-based attack surface | ASVS-713-MEDIUM-003 | Low |
+
+---
+
+## Appendix: Files Analyzed
+
+<details>
+<summary>Click to expand file list</summary>
+
+### Analyzed Files (4)
+
+- `v3/server/pages.py` (relevance: 8)
+- `v3/steve/election.py` (relevance: 6)
+- `v3/steve/crypto.py` (relevance: 5)
+- `v3/docs/schema.md` (relevance: 4)
+
+### Total Repository Statistics
+
+- **Total files:** 49
+- **Relevant files:** 4
+- **Skipped files:** 12
+- **Analysis coverage:** 8.2% of total files, 100% of session-management-relevant files
+
+</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