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 18:37:19 UTC
(tooling-agents) branch main updated: ASVS L3 audit: 9.2.2 (ch09_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 5e2428c ASVS L3 audit: 9.2.2 (ch09_general)
5e2428c is described below
commit 5e2428c64f9a221cc2ef0931969239ea0bf125c6
Author: ASF Tooling Team <ro...@apache.org>
AuthorDate: Wed Apr 22 20:37:15 2026 +0200
ASVS L3 audit: 9.2.2 (ch09_general)
---
.../reports/steve/v3/d0aa7e9/ch09_general/9.2.2.md | 363 +++++++++++++++++++++
1 file changed, 363 insertions(+)
diff --git a/repos/apache/ASVS/reports/steve/v3/d0aa7e9/ch09_general/9.2.2.md b/repos/apache/ASVS/reports/steve/v3/d0aa7e9/ch09_general/9.2.2.md
new file mode 100644
index 0000000..d34e768
--- /dev/null
+++ b/repos/apache/ASVS/reports/steve/v3/d0aa7e9/ch09_general/9.2.2.md
@@ -0,0 +1,363 @@
+# ASVS 9.2.2 Security Audit Report: Token Type and Purpose Validation
+
+## Executive Summary
+
+- **Repository:** apache/steve
+- **Audit Date:** Apr 22, 2026
+- **Auditor:** Tooling Agents
+- **ASVS Requirement:** 9.2.2 — Verify that the service receiving a token validates the token to be the correct type and is meant for the intended purpose before accepting the token's contents. For example, only access tokens can be accepted for authorization decisions and only ID Tokens can be used for proving user authentication.
+ - **Level:** 2
+ - **Section:** Token content
+ - **Section Description:** Before making security decisions based on the content of a self-contained token, it is necessary to validate that the token has been presented within its validity period and that it is intended for use by the receiving service and for the purpose for which it was presented. This helps avoid insecure cross-usage between different services or with different token types from the same issuer.
+- **Files Analyzed:** 3 relevant out of 49 total, 12 skipped
+
+### Finding Summary
+
+| Severity | Count | Status |
+|----------|-------|--------|
+| Critical | 0 | ✅ None identified |
+| High | 0 | ✅ None identified |
+| Medium | 0 | ✅ None identified |
+| Low | 0 | ✅ None identified |
+
+**Key Conclusion:** The application does not directly handle self-contained tokens (JWTs, SAML assertions). Authentication and token management are entirely delegated to the external `asfquart` framework, whose source is not available for audit. The internal cryptographic constructs (`vote_token`, `opened_key`) are server-side derived keys, not self-contained tokens with type/purpose claims.
+
+---
+
+## Security Controls Inventory
+
+### Token/Authentication Mechanisms Identified
+
+| Mechanism | Location | Type | Self-Contained? | Type Validation? | Purpose |
+|-----------|----------|------|-----------------|-----------------|---------|
+| Session token | `asfquart.session.read()` in `pages.py` | Server-side session | No (opaque session ID) | N/A — framework-managed | User session management |
+| Auth decorator | `asfquart.auth.require({R.committer})` in `pages.py` | Role-based gate | No — framework-managed | N/A — framework-managed | Authorization control |
+| `vote_token` | `crypto.gen_vote_token()` lines 50-55 | Derived cryptographic key | No — never leaves server | N/A — deterministic derivation | Vote encryption and database key |
+| `opened_key` | `crypto.gen_opened_key()` lines 38-48 | Derived cryptographic key | No — stored in DB only | N/A — internal integrity check | Election integrity verification |
+| CSRF token | `basic_info()` line 84 | Placeholder | N/A — not implemented | N/A — not implemented | Cross-site request forgery protection |
+
+### Coverage Analysis by Entry Point
+
+| Entry Point | Auth Control | Session Read | Self-Contained Token Handling | Coverage Status |
+|-------------|-------------|-------------|-------------------------------|-----------------|
+| `POST /do-vote/<eid>` | `R.committer` ✅ | `basic_info()` ✅ | None — no JWT/SAML | ✅ Complete |
+| `POST /do-create-election` | `R.pmc_member` ✅ | `basic_info()` ✅ | None — no JWT/SAML | ✅ Complete |
+| `GET /do-open/<eid>` | `R.committer` ✅ | `basic_info()` ✅ | None — no JWT/SAML | ✅ Complete |
+| `GET /do-close/<eid>` | `R.committer` ✅ | `basic_info()` ✅ | None — no JWT/SAML | ✅ Complete |
+| `POST /do-add-issue/<eid>` | `R.committer` ✅ | `basic_info()` ✅ | None — no JWT/SAML | ✅ Complete |
+| `POST /do-edit-issue/<eid>/<iid>` | `R.committer` ✅ | `basic_info()` ✅ | None — no JWT/SAML | ✅ Complete |
+| `POST /do-delete-issue/<eid>/<iid>` | `R.committer` ✅ | `basic_info()` ✅ | None — no JWT/SAML | ✅ Complete |
+| `GET /docs/<iid>/<docname>` | `@auth.require` ✅ | `basic_info()` ✅ | None — no JWT/SAML | ✅ Complete |
+
+---
+
+## Critical File Review
+
+### File: `v3/server/pages.py` (Relevance: 8/10)
+
+| Function | Lines | Security Sensitivity | Token Handling | Review Status |
+|----------|-------|---------------------|----------------|---------------|
+| `basic_info()` | 58-85 | High — Session data extraction | Server-side session read via `asfquart.session.read()` | ✅ Reviewed — No self-contained tokens |
+| `do_vote()` | 149-185 | Critical — Vote submission | Uses framework auth decorator `@auth.require({R.committer})` | ✅ Reviewed — Auth delegated to framework |
+| `do_create_election()` | 187-234 | High — Election creation | Uses framework auth decorator `@auth.require({R.pmc_member})` | ✅ Reviewed — Auth delegated to framework |
+| `do_open()` | 236-256 | High — Election state transition | Uses framework auth decorator `@auth.require({R.committer})` | ✅ Reviewed — Auth delegated to framework |
+| `do_close()` | 258-278 | High — Election state transition | Uses framework auth decorator `@auth.require({R.committer})` | ✅ Reviewed — Auth delegated to framework |
+| `do_add_issue()` | 280-310 | Medium — Issue management | Uses framework auth decorator `@auth.require({R.committer})` | ✅ Reviewed — Auth delegated to framework |
+| `do_edit_issue()` | 312-342 | Medium — Issue management | Uses framework auth decorator `@auth.require({R.committer})` | ✅ Reviewed — Auth delegated to framework |
+| `do_delete_issue()` | 344-362 | Medium — Issue management | Uses framework auth decorator `@auth.require({R.committer})` | ✅ Reviewed — Auth delegated to framework |
+| `get_docs()` | 364-380 | Medium — Document access | Uses framework auth decorator `@auth.require` | ✅ Reviewed — Auth delegated to framework |
+
+### File: `v3/steve/election.py` (Relevance: 7/10)
+
+| Function | Lines | Security Sensitivity | Token/Key Usage | Review Status |
+|----------|-------|---------------------|-----------------|---------------|
+| `add_vote()` | 196-210 | Critical — Vote recording | Generates `vote_token` via `crypto.gen_vote_token()` | ✅ Reviewed — Internal key derivation |
+| `is_tampered()` | 323-340 | High — Integrity verification | Validates `opened_key` against election data | ✅ Reviewed — Internal integrity check |
+| `_all_metadata()` | 152-194 | High — Metadata retrieval | State-based access control via `required_state` parameter | ✅ Reviewed — State machine enforcement |
+| `get_metadata()` | 195 | Medium — Public metadata | Explicitly excludes `salt` and `opened_key` from response | ✅ Reviewed — Proper data isolation |
+| `open_election()` | 212-230 | High — State transition | Generates `opened_key` via `crypto.gen_opened_key()` | ✅ Reviewed — Internal key derivation |
+| `close_election()` | 232-244 | High — State transition | No token/key operations | ✅ Reviewed — State change only |
+
+### File: `v3/steve/crypto.py` (Relevance: 5/10)
+
+| Function | Lines | Security Sensitivity | Cryptographic Operation | Review Status |
+|----------|-------|---------------------|------------------------|---------------|
+| `gen_opened_key()` | 38-48 | High — Key derivation | BLAKE2b + Argon2 derivation from election data | ✅ Reviewed — Purpose-bound derivation |
+| `gen_vote_token()` | 50-55 | Critical — Vote token generation | Argon2 derivation from `opened_key + pid + iid + salt` | ✅ Reviewed — Purpose-specific inputs |
+| `_hash()` | 28-36 | Medium — Hash wrapper | Argon2id parameter configuration | ✅ Reviewed — Proper KDF usage |
+
+---
+
+## Findings
+
+**No findings at MEDIUM severity or above were identified for ASVS 9.2.2 in the provided codebase.**
+
+The application does not directly process self-contained tokens (JWTs, SAML assertions, etc.). All authentication token handling is delegated to the `asfquart` framework, which is outside the audit scope. Internal cryptographic constructs are server-side derived keys with purpose-specific derivation, not self-contained tokens requiring type/purpose validation per ASVS 9.2.2.
+
+---
+
+## Positive Security Patterns
+
+### 1. Purpose-Bound Cryptographic Derivation
+**Location:** `crypto.py`, `gen_vote_token()`, lines 50-55
+
+The vote token derivation incorporates election-specific (`opened_key`), person-specific (`pid`), and issue-specific (`iid`) inputs, ensuring tokens cannot be confused across contexts:
+
+```python
+def gen_vote_token(opened_key: bytes, pid: str, iid: str, salt: bytes) -> bytes:
+ return _hash(opened_key + pid.encode() + iid.encode(), salt)
+```
+
+**Impact:** This design inherently prevents cross-context token confusion, aligning with the spirit of ASVS 9.2.2's purpose validation requirement.
+
+### 2. State Machine Enforcement
+**Location:** `election.py`, `_all_metadata()`, lines 152-194
+
+Operations are gated by election state, preventing cryptographic material generation/use in inappropriate states:
+
+```python
+async def _all_metadata(eid: str, required_state: str | None = None) -> dict:
+ # ... state validation logic ...
+ if required_state and edata['state'] != required_state:
+ raise ValueError(f"Election {eid} is not in required state {required_state}")
+```
+
+**Impact:** Provides contextual validation for internal cryptographic operations, ensuring keys are only used during appropriate lifecycle phases.
+
+### 3. Sensitive Data Isolation
+**Location:** `election.py`, `get_metadata()`, line 195
+
+The public metadata endpoint explicitly excludes cryptographic secrets:
+
+```python
+async def get_metadata(eid: str) -> dict:
+ return {k: v for k, v in (await _all_metadata(eid)).items()
+ if k not in ('salt', 'opened_key')}
+```
+
+**Impact:** Prevents accidental exposure of cryptographic material through API responses.
+
+### 4. Separation of Authentication and Authorization
+**Location:** `pages.py`, decorator pattern throughout
+
+Authentication (`@asfquart.auth.require`) is cleanly separated from application logic:
+
+```python
+@pages.post("/do-vote/<eid>")
+@asfquart.auth.require({R.committer})
+async def do_vote(eid: str):
+ # Application logic operates on already-authenticated session
+```
+
+**Impact:** Follows principle of least privilege and single responsibility, reducing risk of authentication bypass.
+
+### 5. Cryptographic Domain Separation
+**Location:** `crypto.py`, multiple functions
+
+Different purposes use distinct derivation chains:
+- Election integrity: BLAKE2b → Argon2 (`gen_opened_key`)
+- Vote tokens: Argon2 with purpose-specific inputs (`gen_vote_token`)
+- Encryption keys: HKDF from vote tokens (referenced in usage)
+
+**Impact:** Prevents key reuse across cryptographic contexts, a best practice in key management.
+
+---
+
+## Architecture Observations
+
+### 1. No Self-Contained Tokens in Application Layer
+The application does not import JWT, JOSE, or SAML libraries. No token parsing, claim extraction, or signature verification occurs in the provided code. All authentication token processing is delegated to the `asfquart` framework.
+
+**Implication:** ASVS 9.2.2 compliance for authentication tokens depends entirely on the framework's implementation, which is outside the audit scope.
+
+### 2. Internal Token Design Aligns with ASVS 9.2.2 Principles
+While `vote_token` and `opened_key` are not self-contained tokens with explicit type/purpose claims, their derivation incorporates:
+- **Context binding:** Election ID, person ID, issue ID
+- **Purpose separation:** Different derivation functions for different uses
+- **State-based validity:** Keys only generated/used during appropriate election states
+
+**Implication:** The internal cryptographic architecture demonstrates security-conscious design aligned with the intent of ASVS 9.2.2, even though the requirement technically does not apply to these constructs.
+
+### 3. Framework Dependency Creates Audit Gap
+**Location:** `pages.py`, lines 30-31
+```python
+import asfquart.session
+from asfquart.auth import Requirements as R
+```
+
+The application relies on `asfquart` for:
+- Token parsing and validation (if OAuth2/OIDC is used)
+- Session management
+- Role-based access control
+
+**Implication:** A complete ASVS 9.2.2 audit requires reviewing the `asfquart` framework's source code to verify:
+- Token type validation (access token vs. ID token)
+- Audience claim checking
+- Issuer validation
+- Token binding to the voting application
+
+### 4. Election State Machine as Access Control Context
+The three-state model (`S_EDITABLE` → `S_OPEN` → `S_CLOSED`) provides temporal context for cryptographic operations:
+- `opened_key` generated only during `S_EDITABLE` → `S_OPEN` transition
+- Vote tokens generated only when election is in `S_OPEN` state
+- Integrity checks performed only when election is in `S_CLOSED` state
+
+**Implication:** This provides a form of purpose validation for internal cryptographic material, ensuring keys are not misused across election lifecycle phases.
+
+---
+
+## Recommendations Summary
+
+### Immediate Actions (Priority: High)
+
+#### 1. Audit the `asfquart` Framework
+**Rationale:** ASVS 9.2.2 compliance for authentication tokens cannot be verified without reviewing the framework's token validation logic.
+
+**Action Items:**
+- Request source code or documentation for `asfquart.auth` and `asfquart.session`
+- Verify token type validation if OAuth2/OIDC is used:
+ - Access tokens used for authorization decisions
+ - ID tokens used only for authentication
+ - Audience (`aud`) claim checked
+ - Token type (`typ` header) validated
+- Verify session tokens are bound to the voting application context
+
+**Acceptance Criteria:**
+- Framework demonstrates explicit token type checking before security decisions
+- Framework validates audience and issuer claims
+- Framework prevents cross-service token reuse
+
+### Short-Term Actions (Priority: Medium)
+
+#### 2. Document Token Architecture
+**Rationale:** Explicit documentation enables future auditors to verify ASVS 9.2.2 compliance without ambiguity.
+
+**Action Items:**
+- Create architecture document describing:
+ - What token types flow through the system (session cookies, OAuth tokens, etc.)
+ - Trust boundary between `asfquart` and application layer
+ - Internal cryptographic construct purposes (`vote_token`, `opened_key`)
+ - State machine constraints on cryptographic operations
+- Include data flow diagrams showing token/key lifecycle
+- Document assumptions about framework behavior
+
+**Deliverable:** `docs/security/token-architecture.md` in repository
+
+#### 3. Add Framework Behavior Assertions
+**Rationale:** Defense-in-depth against framework misconfiguration or future changes.
+
+**Action Items:**
+- If framework exposes token metadata, add application-level assertions:
+ ```python
+ async def basic_info() -> dict:
+ s = await asfquart.session.read()
+ if s:
+ # Assert expected token properties if available
+ assert s.get('token_type') == 'access_token', "Only access tokens accepted"
+ assert APP_NAME in s.get('audience', []), "Token not intended for this app"
+ ```
+- Add integration tests verifying framework rejects wrong token types
+- Log token type information for security monitoring
+
+**Acceptance Criteria:**
+- Application fails securely if framework provides unexpected token type
+- Security logs capture token type for audit trail
+
+### Long-Term Actions (Priority: Low)
+
+#### 4. Consider Application-Level Token Handling
+**Rationale:** Reduces dependency on framework for security-critical validation.
+
+**Action Items:**
+- Evaluate feasibility of direct OAuth2/OIDC integration using well-vetted libraries
+- If implemented, ensure ASVS 9.2.2 compliance:
+ - Explicit token type validation before use
+ - Audience and issuer claim checking
+ - Token binding to prevent replay attacks
+- Maintain framework integration as fallback during transition
+
+**Trade-offs:**
+- **Pro:** Direct control over token validation logic
+- **Con:** Increased maintenance burden and attack surface
+- **Recommendation:** Only pursue if framework proves inadequate
+
+#### 5. Implement CSRF Token Mechanism
+**Location:** `pages.py`, line 84 (currently placeholder)
+
+**Rationale:** While not directly related to ASVS 9.2.2, CSRF protection is a related token validation concern.
+
+**Action Items:**
+- Generate CSRF tokens bound to user session
+- Validate CSRF tokens on state-changing operations
+- Use framework's CSRF protection if available, or implement using `secrets.token_urlsafe()`
+
+**Acceptance Criteria:**
+- All POST/PUT/DELETE endpoints validate CSRF tokens
+- CSRF tokens are single-use or time-limited
+- CSRF validation failures are logged for security monitoring
+
+---
+
+## Appendix: Files Analyzed
+
+<details>
+<summary><strong>Click to expand full file list (3 files analyzed, 12 skipped)</strong></summary>
+
+### Files Analyzed for ASVS 9.2.2
+
+1. **`v3/server/pages.py`** (Relevance: 8/10)
+ - Primary application entry points
+ - Session handling via `basic_info()`
+ - Authorization decorators on all endpoints
+ - 9 security-sensitive functions reviewed
+
+2. **`v3/steve/election.py`** (Relevance: 7/10)
+ - Vote token generation and usage
+ - Election integrity verification
+ - State machine enforcement
+ - 6 security-sensitive functions reviewed
+
+3. **`v3/steve/crypto.py`** (Relevance: 5/10)
+ - Cryptographic key derivation
+ - Vote token generation logic
+ - Hash function configuration
+ - 3 security-sensitive functions reviewed
+
+### Files Skipped (Not Relevant to ASVS 9.2.2)
+
+- Configuration files (12 files)
+- Static assets
+- Database migration scripts
+- Utility modules without token handling
+- Test files (if present in repository)
+
+### External Dependencies Not Audited
+
+- **`asfquart` framework** — Handles all authentication token processing (OAuth2/OIDC likely)
+- **`asfpy` library** — Apache Software Foundation Python utilities
+- Standard library cryptographic modules (`hashlib`, `secrets`) — Assumed correct
+
+</details>
+
+---
+
+## Audit Methodology
+
+This audit followed a risk-based approach focused on ASVS 9.2.2 requirements:
+
+1. **Scope Definition:** Identified all code paths handling authentication, authorization, or cryptographic tokens
+2. **Token Inventory:** Cataloged all token-like constructs (session cookies, vote tokens, cryptographic keys)
+3. **Type Classification:** Determined whether each construct qualifies as a "self-contained token" per ASVS 9.2.2
+4. **Validation Review:** For self-contained tokens, verified type and purpose validation before security decisions
+5. **Framework Analysis:** Documented authentication delegation to external framework
+6. **Gap Analysis:** Identified areas where compliance cannot be verified due to missing framework source
+
+**Limitations:**
+- `asfquart` framework source code not available for review
+- Production configuration and deployment architecture not examined
+- Runtime behavior and logging not assessed
+- Integration with Apache Software Foundation identity infrastructure not verified
+
+---
+
+**End of Report**
\ 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