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:02:52 UTC
(tooling-agents) branch main updated: ASVS audit: 11.5.1.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 6fd4b73 ASVS audit: 11.5.1.md (redacted)
6fd4b73 is described below
commit 6fd4b73644b7ec3aed950dd97a4b6d4519e62881
Author: ASF Tooling Team <ro...@apache.org>
AuthorDate: Tue May 5 14:02:34 2026 +0200
ASVS audit: 11.5.1.md (redacted)
---
ASVS/reports/steve/v3/d0aa7e9/all/11.5.1.md | 119 ++++++++++++++++++++++++++++
1 file changed, 119 insertions(+)
diff --git a/ASVS/reports/steve/v3/d0aa7e9/all/11.5.1.md b/ASVS/reports/steve/v3/d0aa7e9/all/11.5.1.md
new file mode 100644
index 0000000..8aa9343
--- /dev/null
+++ b/ASVS/reports/steve/v3/d0aa7e9/all/11.5.1.md
@@ -0,0 +1,119 @@
+# Security Audit Report: ASVS 11.5.1
+
+## Executive Summary
+
+| Field | Value |
+|-------|-------|
+| **Repository** | apache/steve/v3 |
+| **Audit Date** | May 05, 2026 |
+| **Auditor** | Tooling Agents (bundled-pass mode) |
+| **ASVS Requirement** | ASVS 11.5.1 |
+| **Files Analyzed** | 8 relevant / 49 total |
+| **Files Skipped** | 12 |
+
+**Requirement description:** Verify that all random numbers and strings which are intended to be non-guessable must be generated using a cryptographically secure pseudo-random number generator (CSPRNG) and have at least 128 bits of entropy. Note that UUIDs do not respect this condition.
+
+### Findings Overview
+
+| Severity | Count |
+|----------|-------|
+| 🔴 Critical | 1 |
+| 🟠 High | 0 |
+| 🟡 Medium | 0 |
+| 🟢 Low | 0 |
+
+---
+
+## ASVS-11.5.1: Random Values - CSPRNG with 128-bit Entropy
+
+### Findings for 11.5.1
+
+### [CRITICAL]
+
+**Finding ID**: ASVS-1151-CRIT-001
+
+**File**: `v3/steve/crypto.py`, function `create_id()`, line 101
+
+**Vulnerable code:**
+```python
+def create_id():
+ "Create a standard ID value."
+
+ # Use 10 hex characters for the ID
+ return secrets.token_hex(5) # 5 bytes
+```
+
+**Data flow**: `secrets.token_hex(5)` → 5 bytes = 40 bits of entropy → used as election IDs (EID) and issue IDs (IID)
+
+**Context from schema.md**:
+> "Non-predictable IDs (eid, iid) use 10-character hex strings to prevent URL guessing."
+> "We do not use AUTOINCREMENT, so that URLs for Elections cannot be deduced."
+
+**Proof of concept**: With only 40 bits of entropy (~1.1 trillion possibilities), a determined attacker can enumerate the ID space. At 10,000 requests/second (common for web applications), the full space could be searched in approximately 12.7 days. For a targeted search with timing information (e.g., knowing approximately when an election was created), the search space is far smaller. An attacker could access election management pages (`/manage/<eid>`) or vote pages (`/vote-on/<eid>`) f [...]
+
+**Impact**: IDs intended to be non-guessable have insufficient entropy. Combined with the incomplete authorization checks throughout `pages.py` (e.g., any authenticated committer can access `/manage/<eid>`), an attacker could enumerate and access elections they shouldn't see or modify.
+
+**Remediation**:
+```python
+def create_id():
+ "Create a standard ID value with sufficient entropy."
+ # Use at least 128 bits of entropy (16 bytes = 32 hex characters)
+ return secrets.token_hex(16) # 16 bytes = 128 bits
+```
+
+Note: This requires updating the database schema CHECK constraint from `length(eid) = 10` to `length(eid) = 32`, and updating the GLOB pattern accordingly.
+
+---
+
+### Security Controls Inventory for 11.5.1
+
+| Control | Location | Coverage Status |
+|---------|----------|-----------------|
+| `secrets.token_bytes(16)` for salt generation | `crypto.py:gen_salt()` line 36 | ✅ Applied at all salt generation points (128 bits) |
+| `secrets.token_hex(5)` for ID generation | `crypto.py:create_id()` line 101 | ⚠️ Applied at all ID generation points BUT only 40 bits |
+| `secrets.randbelow()` for shuffling | `crypto.py:shuffle()` line 93 | ✅ Applied for vote order randomization |
+| `random.shuffle()` for display order | `pages.py` line 269 | ⚠️ Non-CSPRNG but for display order only, not security-sensitive |
+
+**Entry points that call `create_id()`**:
+- `election.py:add_issue()` line 171 — generates IID
+- `election.py:create()` line 379 — generates EID
+
+### Positive Patterns for 11.5.1
+
+1. **Salt generation uses proper CSPRNG**: `gen_salt()` correctly uses `secrets.token_bytes(16)` providing exactly 128 bits of entropy.
+2. **Cryptographic shuffle**: The `shuffle()` function implements Fisher-Yates using `secrets.randbelow()`, providing cryptographically secure randomization of vote order during tally.
+3. **Consistent use of `secrets` module**: The codebase consistently uses `secrets` rather than `random` for security-sensitive operations.
+
+---
+
+
+
+## Cross-cutting Architecture Observations
+
+1. **Cryptographic Design is Sound**: The overall cryptographic architecture (salt generation → Argon2 key derivation → HKDF key stretching → Fernet encryption) follows a well-structured layered approach with proper separation of concerns.
+
+2. **ID Entropy vs. Authorization**: The low entropy in `create_id()` (40 bits) is partially mitigated by the incomplete but intended authorization layer. However, since authz is currently placeholder (`### check authz`), the low-entropy IDs are the *only* barrier to unauthorized access, making the entropy issue more critical in practice.
+
+3. **Consistent Use of CSPRNG**: The codebase consistently uses `secrets` for security-sensitive randomness, with only the candidate display shuffle using `random` (acceptable for non-security display ordering).
+
+4. **Anti-Tamper Mechanism**: The `opened_key` / `is_tampered()` design provides integrity verification for elections, but its effectiveness depends on the security of the underlying Argon2 derivation.
+
+5. **Encryption Transition Planning**: The comments indicate a planned migration from Fernet (AES-128-CBC + HMAC-SHA256) to XChaCha20-Poly1305, which would be an improvement in terms of modern algorithm selection and nonce management.
+
+## Cross-cutting Recommendations
+
+### Immediate (Critical)
+1. **Increase ID entropy to 128 bits**: Change `create_id()` to use `secrets.token_hex(16)` and update the database schema constraints. This is essential given the absence of proper authorization checks.
+
+### Short-term (High)
+2. **Switch from Argon2d to Argon2id**: Change `type=argon2.low_level.Type.D` to `type=argon2.low_level.Type.ID` in the `_hash()` function. This is a one-line change that improves resistance to side-channel attacks per RFC 9106 recommendations.
+
+3. **Implement authorization checks**: The multiple `### check authz` placeholders create false confidence — the decorator-based auth ensures authentication but not authorization (ownership/permission checks).
+
+### Long-term (Medium)
+4. **Memory protection for sensitive operations**: Consider using `mlock()` for memory pages containing decrypted votes during tally operations, and implement explicit memory clearing patterns.
+
+5. **Incremental hashing in `gather_election_data()`**: Refactor to use streaming hash computation instead of accumulating all voter data in memory.
+
+6. **Complete the Fernet → XChaCha20-Poly1305 migration**: As noted in the code comments, this transition would bring the system to a more modern AEAD construction with larger nonce space.
+
\ 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